]> pd.if.org Git - zpackage/commitdiff
bump sqlite to 3.25.1
authorNathan Wagner <nw@hydaspes.if.org>
Mon, 24 Sep 2018 13:05:23 +0000 (13:05 +0000)
committerNathan Wagner <nw@hydaspes.if.org>
Mon, 24 Sep 2018 13:05:23 +0000 (13:05 +0000)
sqlite/shell.c
sqlite/sqlite3.c
sqlite/sqlite3.h

index 678a32a8e2d47b8789ff24aa091d11dc59e00cfb..fb3ac9f43e4ace1c3073374f57c5787f67fd1606 100644 (file)
@@ -97,12 +97,15 @@ typedef unsigned char u8;
 #if (!defined(_WIN32) && !defined(WIN32)) || defined(__MINGW32__)
 # include <unistd.h>
 # include <dirent.h>
+# define GETPID getpid
 # if defined(__MINGW32__)
 #  define DIRENT dirent
 #  ifndef S_ISLNK
 #   define S_ISLNK(mode) (0)
 #  endif
 # endif
+#else
+# define GETPID (int)GetCurrentProcessId
 #endif
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -583,7 +586,7 @@ static char *local_getline(char *zLine, FILE *in){
     if( n+100>nLine ){
       nLine = nLine*2 + 100;
       zLine = realloc(zLine, nLine);
-      if( zLine==0 ) return 0;
+      if( zLine==0 ) shell_out_of_memory();
     }
     if( fgets(&zLine[n], nLine - n, in)==0 ){
       if( n==0 ){
@@ -610,10 +613,7 @@ static char *local_getline(char *zLine, FILE *in){
       int nTrans = strlen30(zTrans)+1;
       if( nTrans>nLine ){
         zLine = realloc(zLine, nTrans);
-        if( zLine==0 ){
-          sqlite3_free(zTrans);
-          return 0;
-        }
+        if( zLine==0 ) shell_out_of_memory();
       }
       memcpy(zLine, zTrans, nTrans);
       sqlite3_free(zTrans);
@@ -760,10 +760,7 @@ static void appendText(ShellText *p, char const *zAppend, char quote){
   if( p->n+len>=p->nAlloc ){
     p->nAlloc = p->nAlloc*2 + len + 20;
     p->z = realloc(p->z, p->nAlloc);
-    if( p->z==0 ){
-      memset(p, 0, sizeof(*p));
-      return;
-    }
+    if( p->z==0 ) shell_out_of_memory();
   }
 
   if( quote ){
@@ -2229,7 +2226,7 @@ static void statTimesToUtc(
   extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*);
   zUnicodeName = sqlite3_win32_utf8_to_unicode(zPath);
   if( zUnicodeName ){
-    memset(&fd, 0, sizeof(WIN32_FIND_DATA));
+    memset(&fd, 0, sizeof(WIN32_FIND_DATAW));
     hFindFile = FindFirstFileW(zUnicodeName, &fd);
     if( hFindFile!=NULL ){
       pStatBuf->st_ctime = (time_t)fileTimeToUnixTime(&fd.ftCreationTime);
@@ -3318,7 +3315,7 @@ static int completionFilter(
       pCur->zPrefix = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg]));
       if( pCur->zPrefix==0 ) return SQLITE_NOMEM;
     }
-    iArg++;
+    iArg = 1;
   }
   if( idxNum & 2 ){
     pCur->nLine = sqlite3_value_bytes(argv[iArg]);
@@ -3326,7 +3323,6 @@ static int completionFilter(
       pCur->zLine = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg]));
       if( pCur->zLine==0 ) return SQLITE_NOMEM;
     }
-    iArg++;
   }
   if( pCur->zLine!=0 && pCur->zPrefix==0 ){
     int i = pCur->nLine;
@@ -8689,6 +8685,7 @@ static void editFunc(
   char *zCmd = 0;
   int bBin;
   int rc;
+  int hasCRNL = 0;
   FILE *f = 0;
   sqlite3_int64 sz;
   sqlite3_int64 x;
@@ -8720,6 +8717,8 @@ static void editFunc(
     }
   }
   bBin = sqlite3_value_type(argv[0])==SQLITE_BLOB;
+  /* When writing the file to be edited, do \n to \r\n conversions on systems
+  ** that want \r\n line endings */
   f = fopen(zTempFile, bBin ? "wb" : "w");
   if( f==0 ){
     sqlite3_result_error(context, "edit() cannot open temp file", -1);
@@ -8729,6 +8728,9 @@ static void editFunc(
   if( bBin ){
     x = fwrite(sqlite3_value_blob(argv[0]), 1, sz, f);
   }else{
+    const char *z = (const char*)sqlite3_value_text(argv[0]);
+    /* Remember whether or not the value originally contained \r\n */
+    if( z && strstr(z,"\r\n")!=0 ) hasCRNL = 1;
     x = fwrite(sqlite3_value_text(argv[0]), 1, sz, f);
   }
   fclose(f);
@@ -8748,7 +8750,7 @@ static void editFunc(
     sqlite3_result_error(context, "EDITOR returned non-zero", -1);
     goto edit_func_end;
   }
-  f = fopen(zTempFile, bBin ? "rb" : "r");
+  f = fopen(zTempFile, "rb");
   if( f==0 ){
     sqlite3_result_error(context,
       "edit() cannot reopen temp file after edit", -1);
@@ -8762,12 +8764,7 @@ static void editFunc(
     sqlite3_result_error_nomem(context);
     goto edit_func_end;
   }
-  if( bBin ){
-    x = fread(p, 1, sz, f);
-  }else{
-    x = fread(p, 1, sz, f);
-    p[sz] = 0;
-  }
+  x = fread(p, 1, sz, f);
   fclose(f);
   f = 0;
   if( x!=sz ){
@@ -8777,6 +8774,20 @@ static void editFunc(
   if( bBin ){
     sqlite3_result_blob64(context, p, sz, sqlite3_free);
   }else{
+    int i, j;
+    if( hasCRNL ){
+      /* If the original contains \r\n then do no conversions back to \n */
+      j = sz;
+    }else{
+      /* If the file did not originally contain \r\n then convert any new
+      ** \r\n back into \n */
+      for(i=j=0; i<sz; i++){
+        if( p[i]=='\r' && p[i+1]=='\n' ) i++;
+        p[j++] = p[i];
+      }
+      sz = j;
+      p[sz] = 0;
+    } 
     sqlite3_result_text64(context, (const char*)p, sz,
                           sqlite3_free, SQLITE_UTF8);
   }
@@ -9535,8 +9546,16 @@ static int shell_callback(
         }else if( aiType && aiType[i]==SQLITE_FLOAT ){
           char z[50];
           double r = sqlite3_column_double(p->pStmt, i);
-          sqlite3_snprintf(50,z,"%!.20g", r);
-          raw_printf(p->out, "%s", z);
+          sqlite3_uint64 ur;
+          memcpy(&ur,&r,sizeof(r));
+          if( ur==0x7ff0000000000000LL ){
+            raw_printf(p->out, "1e999");
+          }else if( ur==0xfff0000000000000LL ){
+            raw_printf(p->out, "-1e999");
+          }else{
+            sqlite3_snprintf(50,z,"%!.20g", r);
+            raw_printf(p->out, "%s", z);
+          }
         }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
           const void *pBlob = sqlite3_column_blob(p->pStmt, i);
           int nBlob = sqlite3_column_bytes(p->pStmt, i);
@@ -10069,8 +10088,7 @@ static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
   int nAlloc = 0;                 /* Allocated size of p->aiIndent[], abYield */
   int iOp;                        /* Index of operation in p->aiIndent[] */
 
-  const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
-                           "NextIfOpen", "PrevIfOpen", 0 };
+  const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 };
   const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead",
                             "Rewind", 0 };
   const char *azGoto[] = { "Goto", 0 };
@@ -10120,7 +10138,9 @@ static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
       }
       nAlloc += 100;
       p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int));
+      if( p->aiIndent==0 ) shell_out_of_memory();
       abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int));
+      if( abYield==0 ) shell_out_of_memory();
     }
     abYield[iOp] = str_in_array(zOp, azYield);
     p->aiIndent[iOp] = 0;
@@ -10474,6 +10494,7 @@ static int shell_exec(
           /* Reprepare pStmt before reactiving trace modes */
           sqlite3_finalize(pStmt);
           sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
+          if( pArg ) pArg->pStmt = pStmt;
         }
         restore_debug_trace_modes();
       }
@@ -11848,6 +11869,7 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
        "SELECT total(length(sql)) FROM %s" },
   };
   int i;
+  unsigned iDataVersion;
   char *zSchemaTab;
   char *zDb = nArg>=2 ? azArg[1] : "main";
   sqlite3_stmt *pStmt = 0;
@@ -11900,6 +11922,8 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
     utf8_printf(p->out, "%-20s %d\n", aQuery[i].zName, val);
   }
   sqlite3_free(zSchemaTab);
+  sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_DATA_VERSION, &iDataVersion);
+  utf8_printf(p->out, "%-20s %u\n", "data version", iDataVersion);
   return 0;
 }
 
@@ -12786,7 +12810,8 @@ static int arExtractCommand(ArCommand *pAr){
     "SELECT "
     " ($dir || name),"
     " writefile(($dir || name), %s, mode, mtime) "
-    "FROM %s WHERE (%s) AND (data IS NULL OR $dirOnly = 0)";
+    "FROM %s WHERE (%s) AND (data IS NULL OR $dirOnly = 0)"
+    " AND name NOT GLOB '*..[/\\]*'";
 
   const char *azExtraArg[] = { 
     "sqlar_uncompress(data, sz)",
@@ -13355,7 +13380,8 @@ static int do_meta_command(char *zLine, ShellState *p){
     const char *zLike = 0;
     int i;
     int savedShowHeader = p->showHeader;
-    ShellClearFlag(p, SHFLG_PreserveRowid|SHFLG_Newlines);
+    int savedShellFlags = p->shellFlgs;
+    ShellClearFlag(p, SHFLG_PreserveRowid|SHFLG_Newlines|SHFLG_Echo);
     for(i=1; i<nArg; i++){
       if( azArg[i][0]=='-' ){
         const char *z = azArg[i]+1;
@@ -13437,6 +13463,7 @@ static int do_meta_command(char *zLine, ShellState *p){
     sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
     raw_printf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n");
     p->showHeader = savedShowHeader;
+    p->shellFlgs = savedShellFlags;
   }else
 
   if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){
@@ -15836,6 +15863,23 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
   stdin_is_interactive = isatty(0);
   stdout_is_console = isatty(1);
 
+#if !defined(_WIN32_WCE)
+  if( getenv("SQLITE_DEBUG_BREAK") ){
+    if( isatty(0) && isatty(2) ){
+      fprintf(stderr,
+          "attach debugger to process %d and press any key to continue.\n",
+          GETPID());
+      fgetc(stdin);
+    }else{
+#if defined(_WIN32) || defined(WIN32)
+      DebugBreak();
+#elif defined(SIGTRAP)
+      raise(SIGTRAP);
+#endif
+    }
+  }
+#endif
+
 #if USE_SYSTEM_SQLITE+0!=1
   if( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){
     utf8_printf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
index ce4f343fdcc2f2eac809ee0a8a3f1cf58272d1d1..d258792d139c0678d9bd1988a5e533897e8cedb3 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
 ** This file is an amalgamation of many separate C source files from SQLite
-** version 3.24.0.  By combining all the individual C code files into this
+** version 3.25.1.  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
 #define CTIMEOPT_VAL_(opt) #opt
 #define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
 
+/* Like CTIMEOPT_VAL, but especially for SQLITE_DEFAULT_LOOKASIDE. This
+** option requires a separate macro because legal values contain a single
+** comma. e.g. (-DSQLITE_DEFAULT_LOOKASIDE="100,100") */
+#define CTIMEOPT_VAL2_(opt1,opt2) #opt1 "," #opt2
+#define CTIMEOPT_VAL2(opt) CTIMEOPT_VAL2_(opt)
+
 /*
 ** An array of names of all compile-time options.  This array should 
 ** be sorted A-Z.
@@ -138,7 +144,7 @@ static const char * const sqlite3azCompileOpt[] = {
   "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
 #endif
 #ifdef SQLITE_DEFAULT_LOOKASIDE
-  "DEFAULT_LOOKASIDE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOOKASIDE),
+  "DEFAULT_LOOKASIDE=" CTIMEOPT_VAL2(SQLITE_DEFAULT_LOOKASIDE),
 #endif
 #if SQLITE_DEFAULT_MEMSTATUS
   "DEFAULT_MEMSTATUS",
@@ -1150,9 +1156,9 @@ extern "C" {
 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
 ** [sqlite_version()] and [sqlite_source_id()].
 */
-#define SQLITE_VERSION        "3.24.0"
-#define SQLITE_VERSION_NUMBER 3024000
-#define SQLITE_SOURCE_ID      "2018-06-04 19:24:41 c7ee0833225bfd8c5ec2f9bf62b97c4e04d03bd9566366d5221ac8fb199a87ca"
+#define SQLITE_VERSION        "3.25.1"
+#define SQLITE_VERSION_NUMBER 3025001
+#define SQLITE_SOURCE_ID      "2018-09-18 20:20:44 2ac9003de44da7dafa3fbb1915ac5725a9275c86bf2f3b7aa19321bf1460b386"
 
 /*
 ** CAPI3REF: Run-Time Library Version Numbers
@@ -1499,6 +1505,7 @@ SQLITE_API int sqlite3_exec(
 */
 #define SQLITE_ERROR_MISSING_COLLSEQ   (SQLITE_ERROR | (1<<8))
 #define SQLITE_ERROR_RETRY             (SQLITE_ERROR | (2<<8))
+#define SQLITE_ERROR_SNAPSHOT          (SQLITE_ERROR | (3<<8))
 #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))
@@ -1538,6 +1545,7 @@ SQLITE_API int sqlite3_exec(
 #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_CANTOPEN_DIRTYWAL       (SQLITE_CANTOPEN | (5<<8)) /* Not Used */
 #define SQLITE_CORRUPT_VTAB            (SQLITE_CORRUPT | (1<<8))
 #define SQLITE_CORRUPT_SEQUENCE        (SQLITE_CORRUPT | (2<<8))
 #define SQLITE_READONLY_RECOVERY       (SQLITE_READONLY | (1<<8))
@@ -1913,7 +1921,8 @@ struct sqlite3_io_methods {
 ** <li>[[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
+** write ahead log ([WAL file]) 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
@@ -2099,6 +2108,26 @@ struct sqlite3_io_methods {
 ** a file lock using the xLock or xShmLock methods of the VFS to wait
 ** for up to M milliseconds before failing, where M is the single 
 ** unsigned integer parameter.
+**
+** <li>[[SQLITE_FCNTL_DATA_VERSION]]
+** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to
+** a database file.  The argument is a pointer to a 32-bit unsigned integer.
+** The "data version" for the pager is written into the pointer.  The
+** "data version" changes whenever any change occurs to the corresponding
+** database file, either through SQL statements on the same database
+** connection or through transactions committed by separate database
+** connections possibly in other processes. The [sqlite3_total_changes()]
+** interface can be used to find if any database on the connection has changed,
+** but that interface responds to changes on TEMP as well as MAIN and does
+** not provide a mechanism to detect changes to MAIN only.  Also, the
+** [sqlite3_total_changes()] interface responds to internal changes only and
+** omits changes made by other database connections.  The
+** [PRAGMA data_version] command provide a mechanism to detect changes to
+** a single attached database that occur due to other database connections,
+** but omits changes implemented by the database connection on which it is
+** called.  This file control is the only mechanism to detect changes that
+** happen either internally or externally and that are associated with
+** a particular attached database.
 ** </ul>
 */
 #define SQLITE_FCNTL_LOCKSTATE               1
@@ -2134,6 +2163,7 @@ struct sqlite3_io_methods {
 #define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE    32
 #define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE  33
 #define SQLITE_FCNTL_LOCK_TIMEOUT           34
+#define SQLITE_FCNTL_DATA_VERSION           35
 
 /* deprecated names */
 #define SQLITE_GET_LOCKPROXYFILE      SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -3148,6 +3178,12 @@ struct sqlite3_mem_methods {
 ** with no schema and no content. The following process works even for
 ** a badly corrupted database file:
 ** <ol>
+** <li> If the database connection is newly opened, make sure it has read the
+**      database schema by preparing then discarding some query against the
+**      database, or calling sqlite3_table_column_metadata(), ignoring any
+**      errors.  This step is only necessary if the application desires to keep
+**      the database in WAL mode after the reset if it was in WAL mode before
+**      the reset.  
 ** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
 ** <li> [sqlite3_exec](db, "[VACUUM]", 0, 0, 0);
 ** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
@@ -3296,12 +3332,17 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
 ** 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.
+**
+** See also:
+** <ul>
+** <li> the [sqlite3_total_changes()] interface
+** <li> the [count_changes pragma]
+** <li> the [changes() SQL function]
+** <li> the [data_version pragma]
+** </ul>
 */
 SQLITE_API int sqlite3_changes(sqlite3*);
 
@@ -3319,13 +3360,26 @@ SQLITE_API int sqlite3_changes(sqlite3*);
 ** 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].
 **
+** This the [sqlite3_total_changes(D)] interface only reports the number
+** of rows that changed due to SQL statement run against database
+** connection D.  Any changes by other database connections are ignored.
+** To detect changes against a database file from other database
+** connections use the [PRAGMA data_version] command or the
+** [SQLITE_FCNTL_DATA_VERSION] [file control].
+** 
 ** If a separate thread makes changes on the same database connection
 ** while [sqlite3_total_changes()] is running then the value
 ** returned is unpredictable and not meaningful.
+**
+** See also:
+** <ul>
+** <li> the [sqlite3_changes()] interface
+** <li> the [count_changes pragma]
+** <li> the [changes() SQL function]
+** <li> the [data_version pragma]
+** <li> the [SQLITE_FCNTL_DATA_VERSION] [file control]
+** </ul>
 */
 SQLITE_API int sqlite3_total_changes(sqlite3*);
 
@@ -4381,13 +4435,24 @@ SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int
 ** [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 values returned by sqlite3_errcode() and/or
+** sqlite3_extended_errcode() might change with each API call.
+** Except, there are some interfaces that are guaranteed to never
+** change the value of the error code.  The error-code preserving
+** interfaces are:
+**
+** <ul>
+** <li> sqlite3_errcode()
+** <li> sqlite3_extended_errcode()
+** <li> sqlite3_errmsg()
+** <li> sqlite3_errmsg16()
+** </ul>
+**
 ** ^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.
@@ -5541,11 +5606,25 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
 ** 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].)^
+** As long as the input parameters are correct, these routines will only
+** fail if an out-of-memory error occurs during a format conversion.
+** Only the following subset of interfaces are subject to out-of-memory
+** errors:
+**
+** <ul>
+** <li> sqlite3_column_blob()
+** <li> sqlite3_column_text()
+** <li> sqlite3_column_text16()
+** <li> sqlite3_column_bytes()
+** <li> sqlite3_column_bytes16()
+** </ul>
+**
+** If an out-of-memory error occurs, then the return value from these
+** routines is the same as if the column had contained an SQL NULL value.
+** Valid SQL NULL returns can be distinguished from out-of-memory errors
+** by invoking the [sqlite3_errcode()] immediately after the suspect
+** return value is obtained and before any
+** other SQLite interface is called on the same [database connection].
 */
 SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
 SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol);
@@ -5622,11 +5701,13 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
 **
 ** ^These functions (collectively known as "function creation routines")
 ** are used to add SQL functions or aggregates or to redefine the behavior
-** of existing SQL functions or aggregates.  The only differences between
-** 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.
+** of existing SQL functions or aggregates. The only differences between
+** the three "sqlite3_create_function*" routines are the text encoding 
+** expected for the second parameter (the name of the function being 
+** created) and the presence or absence of a destructor callback for
+** the application data pointer. Function sqlite3_create_window_function()
+** is similar, but allows the user to supply the extra callback functions
+** needed by [aggregate window functions].
 **
 ** ^The first parameter is the [database connection] to which the SQL
 ** function is to be added.  ^If an application uses more than one database
@@ -5672,7 +5753,8 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
 ** ^(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
+** ^The sixth, seventh and eighth parameters passed to the three
+** "sqlite3_create_function*" functions, 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
@@ -5681,15 +5763,24 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
 ** 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().
+** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue 
+** and xInverse) passed to sqlite3_create_window_function are pointers to
+** C-language callbacks that implement the new function. xStep and xFinal
+** must both be non-NULL. xValue and xInverse may either both be NULL, in
+** which case a regular aggregate function is created, or must both be 
+** non-NULL, in which case the new function may be used as either an aggregate
+** or aggregate window function. More details regarding the implementation
+** of aggregate window functions are 
+** [user-defined window functions|available here].
+**
+** ^(If the final parameter to sqlite3_create_function_v2() or
+** sqlite3_create_window_function() is not NULL, then it is destructor for
+** the application data pointer. The destructor is invoked when the function 
+** is deleted, either by being overloaded or when the database connection 
+** closes.)^ ^The destructor is also invoked if the call to 
+** sqlite3_create_function_v2() fails.  ^When the destructor callback is
+** invoked, it is passed a single argument which is a copy of the application
+** data pointer which was the fifth parameter to sqlite3_create_function_v2().
 **
 ** ^It is permitted to register multiple implementations of the same
 ** functions with the same name but with either differing numbers of
@@ -5742,6 +5833,18 @@ SQLITE_API int sqlite3_create_function_v2(
   void (*xFinal)(sqlite3_context*),
   void(*xDestroy)(void*)
 );
+SQLITE_API int sqlite3_create_window_function(
+  sqlite3 *db,
+  const char *zFunctionName,
+  int nArg,
+  int eTextRep,
+  void *pApp,
+  void (*xStep)(sqlite3_context*,int,sqlite3_value**),
+  void (*xFinal)(sqlite3_context*),
+  void (*xValue)(sqlite3_context*),
+  void (*xInverse)(sqlite3_context*,int,sqlite3_value**),
+  void(*xDestroy)(void*)
+);
 
 /*
 ** CAPI3REF: Text Encodings
@@ -5884,6 +5987,28 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
 **
 ** These routines must be called from the same thread as
 ** the SQL function that supplied the [sqlite3_value*] parameters.
+**
+** As long as the input parameter is correct, these routines can only
+** fail if an out-of-memory error occurs during a format conversion.
+** Only the following subset of interfaces are subject to out-of-memory
+** errors:
+**
+** <ul>
+** <li> sqlite3_value_blob()
+** <li> sqlite3_value_text()
+** <li> sqlite3_value_text16()
+** <li> sqlite3_value_text16le()
+** <li> sqlite3_value_text16be()
+** <li> sqlite3_value_bytes()
+** <li> sqlite3_value_bytes16()
+** </ul>
+**
+** If an out-of-memory error occurs, then the return value from these
+** routines is the same as if the column had contained an SQL NULL value.
+** Valid SQL NULL returns can be distinguished from out-of-memory errors
+** by invoking the [sqlite3_errcode()] immediately after the suspect
+** return value is obtained and before any
+** other SQLite interface is called on the same [database connection].
 */
 SQLITE_API const void *sqlite3_value_blob(sqlite3_value*);
 SQLITE_API double sqlite3_value_double(sqlite3_value*);
@@ -7350,6 +7475,7 @@ struct sqlite3_index_info {
 #define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
 #define SQLITE_INDEX_CONSTRAINT_ISNULL    71
 #define SQLITE_INDEX_CONSTRAINT_IS        72
+#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150
 
 /*
 ** CAPI3REF: Register A Virtual Table Implementation
@@ -8026,6 +8152,7 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
 /*
 ** CAPI3REF: Low-Level Control Of Database Files
 ** METHOD: sqlite3
+** KEYWORDS: {file control}
 **
 ** ^The [sqlite3_file_control()] interface makes a direct call to the
 ** xFileControl method for the [sqlite3_io_methods] object associated
@@ -8040,11 +8167,18 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
 ** the xFileControl method.  ^The return value of the xFileControl
 ** method becomes the return value of this routine.
 **
+** A few opcodes for [sqlite3_file_control()] are handled directly
+** by the SQLite core and never invoke the 
+** sqlite3_io_methods.xFileControl method.
 ** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes
 ** a pointer to the underlying [sqlite3_file] object to be written into
-** 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.
+** the space pointed to by the 4th parameter.  The
+** [SQLITE_FCNTL_JOURNAL_POINTER] works similarly except that it returns
+** the [sqlite3_file] object associated with the journal file instead of
+** the main database.  The [SQLITE_FCNTL_VFS_POINTER] opcode returns
+** a pointer to the underlying [sqlite3_vfs] object for the file.
+** The [SQLITE_FCNTL_DATA_VERSION] returns the data version counter
+** from the pager.
 **
 ** ^If the second parameter (zDbName) does not match the name of any
 ** open database file, then SQLITE_ERROR is returned.  ^This error
@@ -9863,7 +9997,6 @@ 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.
@@ -9880,11 +10013,6 @@ SQLITE_API int sqlite3_system_errno(sqlite3*);
 ** 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];
@@ -9892,7 +10020,7 @@ typedef struct sqlite3_snapshot {
 
 /*
 ** CAPI3REF: Record A Database Snapshot
-** EXPERIMENTAL
+** CONSTRUCTOR: sqlite3_snapshot
 **
 ** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a
 ** new [sqlite3_snapshot] object that records the current state of
@@ -9908,7 +10036,7 @@ typedef struct sqlite3_snapshot {
 ** in this case. 
 **
 ** <ul>
-**   <li> The database handle must be in [autocommit mode].
+**   <li> The database handle must not be in [autocommit mode].
 **
 **   <li> Schema S of [database connection] D must be a [WAL mode] database.
 **
@@ -9931,7 +10059,7 @@ typedef struct sqlite3_snapshot {
 ** to avoid a memory leak.
 **
 ** The [sqlite3_snapshot_get()] interface is only available when the
-** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
+** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used.
 */
 SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
   sqlite3 *db,
@@ -9941,24 +10069,35 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
 
 /*
 ** CAPI3REF: Start a read transaction on an historical snapshot
-** EXPERIMENTAL
+** METHOD: sqlite3_snapshot
+**
+** ^The [sqlite3_snapshot_open(D,S,P)] interface either starts a new read 
+** transaction or upgrades an existing one for schema S of 
+** [database connection] D such that the read transaction refers to 
+** historical [snapshot] P, rather than the most recent change to the 
+** database. ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK 
+** on success or an appropriate [error code] if it fails.
+**
+** ^In order to succeed, the database connection must not be in 
+** [autocommit mode] when [sqlite3_snapshot_open(D,S,P)] is called. If there
+** is already a read transaction open on schema S, then the database handle
+** must have no active statements (SELECT statements that have been passed
+** to sqlite3_step() but not sqlite3_reset() or sqlite3_finalize()). 
+** SQLITE_ERROR is returned if either of these conditions is violated, or
+** if schema S does not exist, or if the snapshot object is invalid.
+**
+** ^A call to sqlite3_snapshot_open() will fail to open if the specified
+** snapshot has been overwritten by a [checkpoint]. In this case 
+** SQLITE_ERROR_SNAPSHOT is returned.
+**
+** If there is already a read transaction open when this function is 
+** invoked, then the same read transaction remains open (on the same
+** database snapshot) if SQLITE_ERROR, SQLITE_BUSY or SQLITE_ERROR_SNAPSHOT
+** is returned. If another error code - for example SQLITE_PROTOCOL or an
+** SQLITE_IOERR error code - is returned, then the final state of the
+** read transaction is undefined. If SQLITE_OK is returned, then the 
+** read transaction is now open on database snapshot P.
 **
-** ^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
@@ -9969,7 +10108,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
 ** 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_ENABLE_SNAPSHOT] compile-time option is used.
 */
 SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open(
   sqlite3 *db,
@@ -9979,20 +10118,20 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open(
 
 /*
 ** CAPI3REF: Destroy a snapshot
-** EXPERIMENTAL
+** DESTRUCTOR: sqlite3_snapshot
 **
 ** ^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_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
+** METHOD: sqlite3_snapshot
 **
 ** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages
 ** of two valid snapshot handles. 
@@ -10011,6 +10150,9 @@ SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*);
 ** 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.
+**
+** This interface is only available if SQLite is compiled with the
+** [SQLITE_ENABLE_SNAPSHOT] option.
 */
 SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
   sqlite3_snapshot *p1,
@@ -10019,23 +10161,26 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
 
 /*
 ** CAPI3REF: Recover snapshots from a wal file
-** EXPERIMENTAL
+** METHOD: sqlite3_snapshot
 **
-** 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.
+** If a [WAL file] remains on disk after all database connections close
+** (either through the use of the [SQLITE_FCNTL_PERSIST_WAL] [file control]
+** or because the last process to have the database opened exited without
+** calling [sqlite3_close()]) and a new connection is subsequently opened
+** on that database and [WAL file], the [sqlite3_snapshot_open()] interface
+** will only be able to open the last transaction added to the WAL file
+** even though the WAL file contains other valid transactions.
 **
-** This function attempts to scan the wal file associated with database zDb
+** 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
+** 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.
+**
+** This interface is only available if SQLite is compiled with the
+** [SQLITE_ENABLE_SNAPSHOT] option.
 */
 SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
 
@@ -10146,7 +10291,7 @@ SQLITE_API int sqlite3_deserialize(
 ** in the P argument is held in memory obtained from [sqlite3_malloc64()]
 ** and that SQLite should take ownership of this memory and automatically
 ** free it when it has finished using it.  Without this flag, the caller
-** is resposible for freeing any dynamically allocated memory.
+** is responsible for freeing any dynamically allocated memory.
 **
 ** The SQLITE_DESERIALIZE_RESIZEABLE flag means that SQLite is allowed to
 ** grow the size of the database using calls to [sqlite3_realloc64()].  This
@@ -12324,7 +12469,7 @@ struct Fts5ExtensionApi {
 **            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
+**            'first + place' or '1st + place', as there are entries in the
 **            FTS index corresponding to both forms of the first token.
 **   </ol>
 **
@@ -12352,7 +12497,7 @@ struct Fts5ExtensionApi {
 **   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:
+**   token "first" is substituted for "1st" by the tokenizer, then the query:
 **
 **   <codeblock>
 **     ... MATCH '1s*'</codeblock>
@@ -13216,94 +13361,104 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
 #define TK_REPLACE                         73
 #define TK_RESTRICT                        74
 #define TK_ROW                             75
-#define TK_TRIGGER                         76
-#define TK_VACUUM                          77
-#define TK_VIEW                            78
-#define TK_VIRTUAL                         79
-#define TK_WITH                            80
-#define TK_REINDEX                         81
-#define TK_RENAME                          82
-#define TK_CTIME_KW                        83
-#define TK_ANY                             84
-#define TK_BITAND                          85
-#define TK_BITOR                           86
-#define TK_LSHIFT                          87
-#define TK_RSHIFT                          88
-#define TK_PLUS                            89
-#define TK_MINUS                           90
-#define TK_STAR                            91
-#define TK_SLASH                           92
-#define TK_REM                             93
-#define TK_CONCAT                          94
-#define TK_COLLATE                         95
-#define TK_BITNOT                          96
-#define TK_ON                              97
-#define TK_INDEXED                         98
-#define TK_STRING                          99
-#define TK_JOIN_KW                        100
-#define TK_CONSTRAINT                     101
-#define TK_DEFAULT                        102
-#define TK_NULL                           103
-#define TK_PRIMARY                        104
-#define TK_UNIQUE                         105
-#define TK_CHECK                          106
-#define TK_REFERENCES                     107
-#define TK_AUTOINCR                       108
-#define TK_INSERT                         109
-#define TK_DELETE                         110
-#define TK_UPDATE                         111
-#define TK_SET                            112
-#define TK_DEFERRABLE                     113
-#define TK_FOREIGN                        114
-#define TK_DROP                           115
-#define TK_UNION                          116
-#define TK_ALL                            117
-#define TK_EXCEPT                         118
-#define TK_INTERSECT                      119
-#define TK_SELECT                         120
-#define TK_VALUES                         121
-#define TK_DISTINCT                       122
-#define TK_DOT                            123
-#define TK_FROM                           124
-#define TK_JOIN                           125
-#define TK_USING                          126
-#define TK_ORDER                          127
-#define TK_GROUP                          128
-#define TK_HAVING                         129
-#define TK_LIMIT                          130
-#define TK_WHERE                          131
-#define TK_INTO                           132
-#define TK_NOTHING                        133
-#define TK_FLOAT                          134
-#define TK_BLOB                           135
-#define TK_INTEGER                        136
-#define TK_VARIABLE                       137
-#define TK_CASE                           138
-#define TK_WHEN                           139
-#define TK_THEN                           140
-#define TK_ELSE                           141
-#define TK_INDEX                          142
-#define TK_ALTER                          143
-#define TK_ADD                            144
-#define TK_TRUEFALSE                      145
-#define TK_ISNOT                          146
-#define TK_FUNCTION                       147
-#define TK_COLUMN                         148
-#define TK_AGG_FUNCTION                   149
-#define TK_AGG_COLUMN                     150
-#define TK_UMINUS                         151
-#define TK_UPLUS                          152
-#define TK_TRUTH                          153
-#define TK_REGISTER                       154
-#define TK_VECTOR                         155
-#define TK_SELECT_COLUMN                  156
-#define TK_IF_NULL_ROW                    157
-#define TK_ASTERISK                       158
-#define TK_SPAN                           159
-#define TK_END_OF_FILE                    160
-#define TK_UNCLOSED_STRING                161
-#define TK_SPACE                          162
-#define TK_ILLEGAL                        163
+#define TK_ROWS                            76
+#define TK_TRIGGER                         77
+#define TK_VACUUM                          78
+#define TK_VIEW                            79
+#define TK_VIRTUAL                         80
+#define TK_WITH                            81
+#define TK_CURRENT                         82
+#define TK_FOLLOWING                       83
+#define TK_PARTITION                       84
+#define TK_PRECEDING                       85
+#define TK_RANGE                           86
+#define TK_UNBOUNDED                       87
+#define TK_REINDEX                         88
+#define TK_RENAME                          89
+#define TK_CTIME_KW                        90
+#define TK_ANY                             91
+#define TK_BITAND                          92
+#define TK_BITOR                           93
+#define TK_LSHIFT                          94
+#define TK_RSHIFT                          95
+#define TK_PLUS                            96
+#define TK_MINUS                           97
+#define TK_STAR                            98
+#define TK_SLASH                           99
+#define TK_REM                            100
+#define TK_CONCAT                         101
+#define TK_COLLATE                        102
+#define TK_BITNOT                         103
+#define TK_ON                             104
+#define TK_INDEXED                        105
+#define TK_STRING                         106
+#define TK_JOIN_KW                        107
+#define TK_CONSTRAINT                     108
+#define TK_DEFAULT                        109
+#define TK_NULL                           110
+#define TK_PRIMARY                        111
+#define TK_UNIQUE                         112
+#define TK_CHECK                          113
+#define TK_REFERENCES                     114
+#define TK_AUTOINCR                       115
+#define TK_INSERT                         116
+#define TK_DELETE                         117
+#define TK_UPDATE                         118
+#define TK_SET                            119
+#define TK_DEFERRABLE                     120
+#define TK_FOREIGN                        121
+#define TK_DROP                           122
+#define TK_UNION                          123
+#define TK_ALL                            124
+#define TK_EXCEPT                         125
+#define TK_INTERSECT                      126
+#define TK_SELECT                         127
+#define TK_VALUES                         128
+#define TK_DISTINCT                       129
+#define TK_DOT                            130
+#define TK_FROM                           131
+#define TK_JOIN                           132
+#define TK_USING                          133
+#define TK_ORDER                          134
+#define TK_GROUP                          135
+#define TK_HAVING                         136
+#define TK_LIMIT                          137
+#define TK_WHERE                          138
+#define TK_INTO                           139
+#define TK_NOTHING                        140
+#define TK_FLOAT                          141
+#define TK_BLOB                           142
+#define TK_INTEGER                        143
+#define TK_VARIABLE                       144
+#define TK_CASE                           145
+#define TK_WHEN                           146
+#define TK_THEN                           147
+#define TK_ELSE                           148
+#define TK_INDEX                          149
+#define TK_ALTER                          150
+#define TK_ADD                            151
+#define TK_WINDOW                         152
+#define TK_OVER                           153
+#define TK_FILTER                         154
+#define TK_TRUEFALSE                      155
+#define TK_ISNOT                          156
+#define TK_FUNCTION                       157
+#define TK_COLUMN                         158
+#define TK_AGG_FUNCTION                   159
+#define TK_AGG_COLUMN                     160
+#define TK_UMINUS                         161
+#define TK_UPLUS                          162
+#define TK_TRUTH                          163
+#define TK_REGISTER                       164
+#define TK_VECTOR                         165
+#define TK_SELECT_COLUMN                  166
+#define TK_IF_NULL_ROW                    167
+#define TK_ASTERISK                       168
+#define TK_SPAN                           169
+#define TK_END_OF_FILE                    170
+#define TK_UNCLOSED_STRING                171
+#define TK_SPACE                          172
+#define TK_ILLEGAL                        173
 
 /* The token codes above must all fit in 8 bits */
 #define TKFLG_MASK           0xff  
@@ -13577,7 +13732,8 @@ typedef INT16_TYPE LogEst;
 # if defined(__SIZEOF_POINTER__)
 #   define SQLITE_PTRSIZE __SIZEOF_POINTER__
 # elif defined(i386)     || defined(__i386__)   || defined(_M_IX86) ||    \
-       defined(_M_ARM)   || defined(__arm__)    || defined(__x86)
+       defined(_M_ARM)   || defined(__arm__)    || defined(__x86)   ||    \
+      (defined(__TOS_AIX__) && !defined(__64BIT__))
 #   define SQLITE_PTRSIZE 4
 # else
 #   define SQLITE_PTRSIZE 8
@@ -13618,7 +13774,7 @@ typedef INT16_TYPE LogEst;
 # 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__)
+     defined(__arm__)  || defined(_M_ARM64)
 #   define SQLITE_BYTEORDER    1234
 # elif defined(sparc)    || defined(__ppc__)
 #   define SQLITE_BYTEORDER    4321
@@ -13873,6 +14029,7 @@ typedef struct NameContext NameContext;
 typedef struct Parse Parse;
 typedef struct PreUpdate PreUpdate;
 typedef struct PrintfArguments PrintfArguments;
+typedef struct RenameToken RenameToken;
 typedef struct RowSet RowSet;
 typedef struct Savepoint Savepoint;
 typedef struct Select Select;
@@ -13893,8 +14050,35 @@ typedef struct VTable VTable;
 typedef struct VtabCtx VtabCtx;
 typedef struct Walker Walker;
 typedef struct WhereInfo WhereInfo;
+typedef struct Window Window;
 typedef struct With With;
 
+
+/*
+** 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)
+
 /* 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
@@ -13990,7 +14174,7 @@ 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 sqlite3BtreeBeginTrans(Btree*,int,int*);
 SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
 SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*, int);
 SQLITE_PRIVATE int sqlite3BtreeCommit(Btree*);
@@ -14213,6 +14397,9 @@ struct BtreePayload {
 SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload,
                        int flags, int seekResult);
 SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor*, int *pRes);
+#ifndef SQLITE_OMIT_WINDOWFUNC
+SQLITE_PRIVATE void sqlite3BtreeSkipNext(BtCursor*);
+#endif
 SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor*, int *pRes);
 SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int flags);
 SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor*);
@@ -14380,7 +14567,8 @@ struct VdbeOp {
   u64 cycles;              /* Total time spent executing this instruction */
 #endif
 #ifdef SQLITE_VDBE_COVERAGE
-  int iSrcLine;            /* Source-code line that generated this opcode */
+  u32 iSrcLine;            /* Source-code line that generated this opcode
+                           ** with flags in the upper 8 bits */
 #endif
 };
 typedef struct VdbeOp VdbeOp;
@@ -14481,52 +14669,52 @@ typedef struct VdbeOpList VdbeOpList;
 #define OP_AutoCommit      1
 #define OP_Transaction     2
 #define OP_SorterNext      3 /* jump                                       */
-#define OP_PrevIfOpen      4 /* jump                                       */
-#define OP_NextIfOpen      5 /* jump                                       */
-#define OP_Prev            6 /* jump                                       */
-#define OP_Next            7 /* jump                                       */
-#define OP_Checkpoint      8
-#define OP_JournalMode     9
-#define OP_Vacuum         10
-#define OP_VFilter        11 /* jump, synopsis: iplan=r[P3] zplan='P4'     */
-#define OP_VUpdate        12 /* synopsis: data=r[P3@P2]                    */
-#define OP_Goto           13 /* jump                                       */
-#define OP_Gosub          14 /* jump                                       */
-#define OP_InitCoroutine  15 /* jump                                       */
-#define OP_Yield          16 /* jump                                       */
-#define OP_MustBeInt      17 /* jump                                       */
-#define OP_Jump           18 /* jump                                       */
+#define OP_Prev            4 /* jump                                       */
+#define OP_Next            5 /* jump                                       */
+#define OP_Checkpoint      6
+#define OP_JournalMode     7
+#define OP_Vacuum          8
+#define OP_VFilter         9 /* jump, synopsis: iplan=r[P3] zplan='P4'     */
+#define OP_VUpdate        10 /* synopsis: data=r[P3@P2]                    */
+#define OP_Goto           11 /* jump                                       */
+#define OP_Gosub          12 /* jump                                       */
+#define OP_InitCoroutine  13 /* jump                                       */
+#define OP_Yield          14 /* jump                                       */
+#define OP_MustBeInt      15 /* jump                                       */
+#define OP_Jump           16 /* jump                                       */
+#define OP_Once           17 /* jump                                       */
+#define OP_If             18 /* jump                                       */
 #define OP_Not            19 /* same as TK_NOT, synopsis: r[P2]= !r[P1]    */
-#define OP_Once           20 /* jump                                       */
-#define OP_If             21 /* jump                                       */
-#define OP_IfNot          22 /* jump                                       */
-#define OP_IfNullRow      23 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
-#define OP_SeekLT         24 /* jump, synopsis: key=r[P3@P4]               */
-#define OP_SeekLE         25 /* jump, synopsis: key=r[P3@P4]               */
-#define OP_SeekGE         26 /* jump, synopsis: key=r[P3@P4]               */
-#define OP_SeekGT         27 /* jump, synopsis: key=r[P3@P4]               */
-#define OP_NoConflict     28 /* jump, synopsis: key=r[P3@P4]               */
-#define OP_NotFound       29 /* jump, synopsis: key=r[P3@P4]               */
-#define OP_Found          30 /* jump, synopsis: key=r[P3@P4]               */
-#define OP_SeekRowid      31 /* jump, synopsis: intkey=r[P3]               */
-#define OP_NotExists      32 /* jump, synopsis: intkey=r[P3]               */
-#define OP_Last           33 /* jump                                       */
-#define OP_IfSmaller      34 /* jump                                       */
-#define OP_SorterSort     35 /* jump                                       */
-#define OP_Sort           36 /* jump                                       */
-#define OP_Rewind         37 /* jump                                       */
-#define OP_IdxLE          38 /* jump, synopsis: key=r[P3@P4]               */
-#define OP_IdxGT          39 /* jump, synopsis: key=r[P3@P4]               */
-#define OP_IdxLT          40 /* jump, synopsis: key=r[P3@P4]               */
-#define OP_IdxGE          41 /* jump, synopsis: key=r[P3@P4]               */
-#define OP_RowSetRead     42 /* jump, synopsis: r[P3]=rowset(P1)           */
+#define OP_IfNot          20 /* jump                                       */
+#define OP_IfNullRow      21 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
+#define OP_SeekLT         22 /* jump, synopsis: key=r[P3@P4]               */
+#define OP_SeekLE         23 /* jump, synopsis: key=r[P3@P4]               */
+#define OP_SeekGE         24 /* jump, synopsis: key=r[P3@P4]               */
+#define OP_SeekGT         25 /* jump, synopsis: key=r[P3@P4]               */
+#define OP_IfNoHope       26 /* jump, synopsis: key=r[P3@P4]               */
+#define OP_NoConflict     27 /* jump, synopsis: key=r[P3@P4]               */
+#define OP_NotFound       28 /* jump, synopsis: key=r[P3@P4]               */
+#define OP_Found          29 /* jump, synopsis: key=r[P3@P4]               */
+#define OP_SeekRowid      30 /* jump, synopsis: intkey=r[P3]               */
+#define OP_NotExists      31 /* jump, synopsis: intkey=r[P3]               */
+#define OP_Last           32 /* jump                                       */
+#define OP_IfSmaller      33 /* jump                                       */
+#define OP_SorterSort     34 /* jump                                       */
+#define OP_Sort           35 /* jump                                       */
+#define OP_Rewind         36 /* jump                                       */
+#define OP_IdxLE          37 /* jump, synopsis: key=r[P3@P4]               */
+#define OP_IdxGT          38 /* jump, synopsis: key=r[P3@P4]               */
+#define OP_IdxLT          39 /* jump, synopsis: key=r[P3@P4]               */
+#define OP_IdxGE          40 /* jump, synopsis: key=r[P3@P4]               */
+#define OP_RowSetRead     41 /* jump, synopsis: r[P3]=rowset(P1)           */
+#define OP_RowSetTest     42 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */
 #define OP_Or             43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
 #define OP_And            44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
-#define OP_RowSetTest     45 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */
-#define OP_Program        46 /* jump                                       */
-#define OP_FkIfZero       47 /* jump, synopsis: if fkctr[P1]==0 goto P2    */
-#define OP_IfPos          48 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
-#define OP_IfNotZero      49 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
+#define OP_Program        45 /* jump                                       */
+#define OP_FkIfZero       46 /* jump, synopsis: if fkctr[P1]==0 goto P2    */
+#define OP_IfPos          47 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
+#define OP_IfNotZero      48 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
+#define OP_DecrJumpZero   49 /* jump, synopsis: if (--r[P1])==0 goto P2    */
 #define OP_IsNull         50 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
 #define OP_NotNull        51 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
 #define OP_Ne             52 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */
@@ -14536,119 +14724,121 @@ typedef struct VdbeOpList VdbeOpList;
 #define OP_Lt             56 /* jump, same as TK_LT, synopsis: IF r[P3]<r[P1] */
 #define OP_Ge             57 /* jump, same as TK_GE, synopsis: IF r[P3]>=r[P1] */
 #define OP_ElseNotEq      58 /* jump, same as TK_ESCAPE                    */
-#define OP_DecrJumpZero   59 /* jump, synopsis: if (--r[P1])==0 goto P2    */
-#define OP_IncrVacuum     60 /* jump                                       */
-#define OP_VNext          61 /* jump                                       */
-#define OP_Init           62 /* jump, synopsis: Start at P2                */
-#define OP_Return         63
-#define OP_EndCoroutine   64
-#define OP_HaltIfNull     65 /* synopsis: if r[P3]=null halt               */
-#define OP_Halt           66
-#define OP_Integer        67 /* synopsis: r[P2]=P1                         */
-#define OP_Int64          68 /* synopsis: r[P2]=P4                         */
-#define OP_String         69 /* synopsis: r[P2]='P4' (len=P1)              */
-#define OP_Null           70 /* synopsis: r[P2..P3]=NULL                   */
-#define OP_SoftNull       71 /* synopsis: r[P1]=NULL                       */
-#define OP_Blob           72 /* synopsis: r[P2]=P4 (len=P1)                */
-#define OP_Variable       73 /* synopsis: r[P2]=parameter(P1,P4)           */
-#define OP_Move           74 /* synopsis: r[P2@P3]=r[P1@P3]                */
-#define OP_Copy           75 /* synopsis: r[P2@P3+1]=r[P1@P3+1]            */
-#define OP_SCopy          76 /* synopsis: r[P2]=r[P1]                      */
-#define OP_IntCopy        77 /* synopsis: r[P2]=r[P1]                      */
-#define OP_ResultRow      78 /* synopsis: output=r[P1@P2]                  */
-#define OP_CollSeq        79
-#define OP_AddImm         80 /* synopsis: r[P1]=r[P1]+P2                   */
-#define OP_RealAffinity   81
-#define OP_Cast           82 /* synopsis: affinity(r[P1])                  */
-#define OP_Permutation    83
-#define OP_Compare        84 /* synopsis: r[P1@P3] <-> r[P2@P3]            */
-#define OP_BitAnd         85 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
-#define OP_BitOr          86 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
-#define OP_ShiftLeft      87 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
-#define OP_ShiftRight     88 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
-#define OP_Add            89 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
-#define OP_Subtract       90 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
-#define OP_Multiply       91 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
-#define OP_Divide         92 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
-#define OP_Remainder      93 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
-#define OP_Concat         94 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
-#define OP_IsTrue         95 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */
-#define OP_BitNot         96 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */
-#define OP_Offset         97 /* synopsis: r[P3] = sqlite_offset(P1)        */
-#define OP_Column         98 /* synopsis: r[P3]=PX                         */
-#define OP_String8        99 /* same as TK_STRING, synopsis: r[P2]='P4'    */
-#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_SeekEnd       127
-#define OP_SorterInsert  128 /* synopsis: key=r[P2]                        */
-#define OP_IdxInsert     129 /* synopsis: key=r[P2]                        */
-#define OP_IdxDelete     130 /* synopsis: key=r[P2@P3]                     */
-#define OP_DeferredSeek  131 /* synopsis: Move P3 to P1.rowid if needed    */
-#define OP_IdxRowid      132 /* synopsis: r[P2]=rowid                      */
-#define OP_Destroy       133
-#define OP_Real          134 /* same as TK_FLOAT, synopsis: r[P2]=P4       */
-#define OP_Clear         135
-#define OP_ResetSorter   136
-#define OP_CreateBtree   137 /* synopsis: r[P2]=root iDb=P1 flags=P3       */
-#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_PureFunc0     163
-#define OP_Function0     164 /* synopsis: r[P3]=func(r[P2@P5])             */
-#define OP_PureFunc      165
-#define OP_Function      166 /* synopsis: r[P3]=func(r[P2@P5])             */
-#define OP_Trace         167
-#define OP_CursorHint    168
-#define OP_Noop          169
-#define OP_Explain       170
-#define OP_Abortable     171
+#define OP_IncrVacuum     59 /* jump                                       */
+#define OP_VNext          60 /* jump                                       */
+#define OP_Init           61 /* jump, synopsis: Start at P2                */
+#define OP_PureFunc0      62
+#define OP_Function0      63 /* synopsis: r[P3]=func(r[P2@P5])             */
+#define OP_PureFunc       64
+#define OP_Function       65 /* synopsis: r[P3]=func(r[P2@P5])             */
+#define OP_Return         66
+#define OP_EndCoroutine   67
+#define OP_HaltIfNull     68 /* synopsis: if r[P3]=null halt               */
+#define OP_Halt           69
+#define OP_Integer        70 /* synopsis: r[P2]=P1                         */
+#define OP_Int64          71 /* synopsis: r[P2]=P4                         */
+#define OP_String         72 /* synopsis: r[P2]='P4' (len=P1)              */
+#define OP_Null           73 /* synopsis: r[P2..P3]=NULL                   */
+#define OP_SoftNull       74 /* synopsis: r[P1]=NULL                       */
+#define OP_Blob           75 /* synopsis: r[P2]=P4 (len=P1)                */
+#define OP_Variable       76 /* synopsis: r[P2]=parameter(P1,P4)           */
+#define OP_Move           77 /* synopsis: r[P2@P3]=r[P1@P3]                */
+#define OP_Copy           78 /* synopsis: r[P2@P3+1]=r[P1@P3+1]            */
+#define OP_SCopy          79 /* synopsis: r[P2]=r[P1]                      */
+#define OP_IntCopy        80 /* synopsis: r[P2]=r[P1]                      */
+#define OP_ResultRow      81 /* synopsis: output=r[P1@P2]                  */
+#define OP_CollSeq        82
+#define OP_AddImm         83 /* synopsis: r[P1]=r[P1]+P2                   */
+#define OP_RealAffinity   84
+#define OP_Cast           85 /* synopsis: affinity(r[P1])                  */
+#define OP_Permutation    86
+#define OP_Compare        87 /* synopsis: r[P1@P3] <-> r[P2@P3]            */
+#define OP_IsTrue         88 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */
+#define OP_Offset         89 /* synopsis: r[P3] = sqlite_offset(P1)        */
+#define OP_Column         90 /* synopsis: r[P3]=PX                         */
+#define OP_Affinity       91 /* synopsis: affinity(r[P1@P2])               */
+#define OP_BitAnd         92 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
+#define OP_BitOr          93 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
+#define OP_ShiftLeft      94 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
+#define OP_ShiftRight     95 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
+#define OP_Add            96 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
+#define OP_Subtract       97 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
+#define OP_Multiply       98 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
+#define OP_Divide         99 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
+#define OP_Remainder     100 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
+#define OP_Concat        101 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
+#define OP_MakeRecord    102 /* synopsis: r[P3]=mkrec(r[P1@P2])            */
+#define OP_BitNot        103 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */
+#define OP_Count         104 /* synopsis: r[P2]=count()                    */
+#define OP_ReadCookie    105
+#define OP_String8       106 /* same as TK_STRING, synopsis: r[P2]='P4'    */
+#define OP_SetCookie     107
+#define OP_ReopenIdx     108 /* synopsis: root=P2 iDb=P3                   */
+#define OP_OpenRead      109 /* synopsis: root=P2 iDb=P3                   */
+#define OP_OpenWrite     110 /* synopsis: root=P2 iDb=P3                   */
+#define OP_OpenDup       111
+#define OP_OpenAutoindex 112 /* synopsis: nColumn=P2                       */
+#define OP_OpenEphemeral 113 /* synopsis: nColumn=P2                       */
+#define OP_SorterOpen    114
+#define OP_SequenceTest  115 /* synopsis: if( cursor[P1].ctr++ ) pc = P2   */
+#define OP_OpenPseudo    116 /* synopsis: P3 columns in r[P2]              */
+#define OP_Close         117
+#define OP_ColumnsUsed   118
+#define OP_SeekHit       119 /* synopsis: seekHit=P2                       */
+#define OP_Sequence      120 /* synopsis: r[P2]=cursor[P1].ctr++           */
+#define OP_NewRowid      121 /* synopsis: r[P2]=rowid                      */
+#define OP_Insert        122 /* synopsis: intkey=r[P3] data=r[P2]          */
+#define OP_InsertInt     123 /* synopsis: intkey=P3 data=r[P2]             */
+#define OP_Delete        124
+#define OP_ResetCount    125
+#define OP_SorterCompare 126 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
+#define OP_SorterData    127 /* synopsis: r[P2]=data                       */
+#define OP_RowData       128 /* synopsis: r[P2]=data                       */
+#define OP_Rowid         129 /* synopsis: r[P2]=rowid                      */
+#define OP_NullRow       130
+#define OP_SeekEnd       131
+#define OP_SorterInsert  132 /* synopsis: key=r[P2]                        */
+#define OP_IdxInsert     133 /* synopsis: key=r[P2]                        */
+#define OP_IdxDelete     134 /* synopsis: key=r[P2@P3]                     */
+#define OP_DeferredSeek  135 /* synopsis: Move P3 to P1.rowid if needed    */
+#define OP_IdxRowid      136 /* synopsis: r[P2]=rowid                      */
+#define OP_Destroy       137
+#define OP_Clear         138
+#define OP_ResetSorter   139
+#define OP_CreateBtree   140 /* synopsis: r[P2]=root iDb=P1 flags=P3       */
+#define OP_Real          141 /* same as TK_FLOAT, synopsis: r[P2]=P4       */
+#define OP_SqlExec       142
+#define OP_ParseSchema   143
+#define OP_LoadAnalysis  144
+#define OP_DropTable     145
+#define OP_DropIndex     146
+#define OP_DropTrigger   147
+#define OP_IntegrityCk   148
+#define OP_RowSetAdd     149 /* synopsis: rowset(P1)=r[P2]                 */
+#define OP_Param         150
+#define OP_FkCounter     151 /* synopsis: fkctr[P1]+=P2                    */
+#define OP_MemMax        152 /* synopsis: r[P1]=max(r[P1],r[P2])           */
+#define OP_OffsetLimit   153 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
+#define OP_AggInverse    154 /* synopsis: accum=r[P3] inverse(r[P2@P5])    */
+#define OP_AggStep       155 /* synopsis: accum=r[P3] step(r[P2@P5])       */
+#define OP_AggStep1      156 /* synopsis: accum=r[P3] step(r[P2@P5])       */
+#define OP_AggValue      157 /* synopsis: r[P3]=value N=P2                 */
+#define OP_AggFinal      158 /* synopsis: accum=r[P1] N=P2                 */
+#define OP_Expire        159
+#define OP_TableLock     160 /* synopsis: iDb=P1 root=P2 write=P3          */
+#define OP_VBegin        161
+#define OP_VCreate       162
+#define OP_VDestroy      163
+#define OP_VOpen         164
+#define OP_VColumn       165 /* synopsis: r[P3]=vcolumn(P2)                */
+#define OP_VRename       166
+#define OP_Pagecount     167
+#define OP_MaxPgcnt      168
+#define OP_Trace         169
+#define OP_CursorHint    170
+#define OP_Noop          171
+#define OP_Explain       172
+#define OP_Abortable     173
 
 /* Properties such as "out2" or "jump" that are specified in
 ** comments following the "case" for each opcode in the vdbe.c
@@ -14661,28 +14851,28 @@ typedef struct VdbeOpList VdbeOpList;
 #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,\
+/*   0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x10,\
+/*   8 */ 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x03, 0x03,\
+/*  16 */ 0x01, 0x01, 0x03, 0x12, 0x03, 0x01, 0x09, 0x09,\
 /*  24 */ 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,\
-/*  32 */ 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\
-/*  40 */ 0x01, 0x01, 0x23, 0x26, 0x26, 0x0b, 0x01, 0x01,\
+/*  32 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\
+/*  40 */ 0x01, 0x23, 0x0b, 0x26, 0x26, 0x01, 0x01, 0x03,\
 /*  48 */ 0x03, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
-/*  56 */ 0x0b, 0x0b, 0x01, 0x03, 0x01, 0x01, 0x01, 0x02,\
-/*  64 */ 0x02, 0x08, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00,\
-/*  72 */ 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\
-/*  80 */ 0x02, 0x02, 0x02, 0x00, 0x00, 0x26, 0x26, 0x26,\
-/*  88 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x12,\
-/*  96 */ 0x12, 0x20, 0x00, 0x10, 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, 0x00,\
-/* 128 */ 0x04, 0x04, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00,\
-/* 136 */ 0x00, 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, 0x00, 0x00,\
-/* 168 */ 0x00, 0x00, 0x00, 0x00,}
+/*  56 */ 0x0b, 0x0b, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,\
+/*  64 */ 0x00, 0x00, 0x02, 0x02, 0x08, 0x00, 0x10, 0x10,\
+/*  72 */ 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10,\
+/*  80 */ 0x10, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,\
+/*  88 */ 0x12, 0x20, 0x00, 0x00, 0x26, 0x26, 0x26, 0x26,\
+/*  96 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x00, 0x12,\
+/* 104 */ 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 112 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 120 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 128 */ 0x00, 0x10, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00,\
+/* 136 */ 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\
+/* 144 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x10, 0x00,\
+/* 152 */ 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 160 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\
+/* 168 */ 0x10, 0x00, 0x00, 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
@@ -14690,7 +14880,7 @@ typedef struct VdbeOpList VdbeOpList;
 ** generated this include file strives to group all JUMP opcodes
 ** together near the beginning of the list.
 */
-#define SQLITE_MX_JUMP_OPCODE  62  /* Maximum JUMP opcode */
+#define SQLITE_MX_JUMP_OPCODE  61  /* Maximum JUMP opcode */
 
 /************** End of opcodes.h *********************************************/
 /************** Continuing where we left off in vdbe.h ***********************/
@@ -14764,9 +14954,6 @@ SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3*,Vdbe*);
 SQLITE_PRIVATE void sqlite3VdbeMakeReady(Vdbe*,Parse*);
 SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe*);
 SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe*, int);
-#ifdef SQLITE_COVERAGE_TEST
-SQLITE_PRIVATE   int sqlite3VdbeLabelHasBeenResolved(Vdbe*,int);
-#endif
 SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe*);
 #ifdef SQLITE_DEBUG
 SQLITE_PRIVATE   int sqlite3VdbeAssertMayAbort(Vdbe *, int);
@@ -14788,6 +14975,7 @@ SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe*, int);
 SQLITE_PRIVATE   char *sqlite3VdbeExpandSql(Vdbe*, const char*);
 #endif
 SQLITE_PRIVATE int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
+SQLITE_PRIVATE int sqlite3BlobCompare(const Mem*, const Mem*);
 
 SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*);
 SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*);
@@ -14843,23 +15031,52 @@ SQLITE_PRIVATE   void sqlite3VdbeNoopComment(Vdbe*, const char*, ...);
 **
 **    VdbeCoverageNeverTaken(v)        // Previous branch is never taken
 **
+**    VdbeCoverageNeverNull(v)         // Previous three-way branch is only
+**                                     // taken on the first two ways.  The
+**                                     // NULL option is not possible
+**
+**    VdbeCoverageEqNe(v)              // Previous OP_Jump is only interested
+**                                     // in distingishing equal and not-equal.
+**
 ** Every VDBE branch operation must be tagged with one of the macros above.
 ** If not, then when "make test" is run with -DSQLITE_VDBE_COVERAGE and
 ** -DSQLITE_DEBUG then an ALWAYS() will fail in the vdbeTakeBranch()
 ** routine in vdbe.c, alerting the developer to the missed tag.
+**
+** During testing, the test application will invoke
+** sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE,...) to set a callback
+** routine that is invoked as each bytecode branch is taken.  The callback
+** contains the sqlite3.c source line number ov the VdbeCoverage macro and
+** flags to indicate whether or not the branch was taken.  The test application
+** is responsible for keeping track of this and reporting byte-code branches
+** that are never taken.
+**
+** See the VdbeBranchTaken() macro and vdbeTakeBranch() function in the
+** vdbe.c source file for additional information.
 */
 #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 VdbeCoverageAlwaysTaken(v) \
+         sqlite3VdbeSetLineNumber(v,__LINE__|0x5000000);
+# define VdbeCoverageNeverTaken(v) \
+         sqlite3VdbeSetLineNumber(v,__LINE__|0x6000000);
+# define VdbeCoverageNeverNull(v) \
+         sqlite3VdbeSetLineNumber(v,__LINE__|0x4000000);
+# define VdbeCoverageNeverNullIf(v,x) \
+         if(x)sqlite3VdbeSetLineNumber(v,__LINE__|0x4000000);
+# define VdbeCoverageEqNe(v) \
+         sqlite3VdbeSetLineNumber(v,__LINE__|0x8000000);
 # define VDBE_OFFSET_LINENO(x) (__LINE__+x)
 #else
 # define VdbeCoverage(v)
 # define VdbeCoverageIf(v,x)
 # define VdbeCoverageAlwaysTaken(v)
 # define VdbeCoverageNeverTaken(v)
+# define VdbeCoverageNeverNull(v)
+# define VdbeCoverageNeverNullIf(v,x)
+# define VdbeCoverageEqNe(v)
 # define VDBE_OFFSET_LINENO(x) 0
 #endif
 
@@ -14869,6 +15086,10 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const ch
 # define sqlite3VdbeScanStatus(a,b,c,d,e)
 #endif
 
+#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
+SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, VdbeOp*);
+#endif
+
 #endif /* SQLITE_VDBE_H */
 
 /************** End of vdbe.h ************************************************/
@@ -15063,6 +15284,8 @@ SQLITE_PRIVATE   int sqlite3PagerUseWal(Pager *pPager, Pgno);
 SQLITE_PRIVATE   int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot);
 SQLITE_PRIVATE   int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot);
 SQLITE_PRIVATE   int sqlite3PagerSnapshotRecover(Pager *pPager);
+SQLITE_PRIVATE   int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot);
+SQLITE_PRIVATE   void sqlite3PagerSnapshotUnlock(Pager *pPager);
 # endif
 #else
 # define sqlite3PagerUseWal(x,y) 0
@@ -16070,7 +16293,7 @@ struct sqlite3 {
 ** selectively disable various optimizations.
 */
 #define SQLITE_QueryFlattener 0x0001   /* Query flattening */
-#define SQLITE_ColumnCache    0x0002   /* Column cache */
+                          /*  0x0002   available for reuse */
 #define SQLITE_GroupByOrder   0x0004   /* GROUPBY cover of ORDERBY */
 #define SQLITE_FactorOutConst 0x0008   /* Constant factoring */
 #define SQLITE_DistinctOpt    0x0010   /* DISTINCT using indexes */
@@ -16084,6 +16307,8 @@ struct sqlite3 {
    /* TH3 expects the Stat34  ^^^^^^ value to be 0x0800.  Don't change it */
 #define SQLITE_PushDown       0x1000   /* The push-down optimization */
 #define SQLITE_SimplifyJoin   0x2000   /* Convert LEFT JOIN to JOIN */
+#define SQLITE_SkipScan       0x4000   /* Skip-scans */
+#define SQLITE_PropagateConst 0x8000   /* The constant propagation opt */
 #define SQLITE_AllOpts        0xffff   /* All optimizations */
 
 /*
@@ -16122,11 +16347,13 @@ struct sqlite3 {
 */
 struct FuncDef {
   i8 nArg;             /* Number of arguments.  -1 means unlimited */
-  u16 funcFlags;       /* Some combination of SQLITE_FUNC_* */
+  u32 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 */
+  void (*xValue)(sqlite3_context*);                     /* Current agg value */
+  void (*xInverse)(sqlite3_context*,int,sqlite3_value**); /* inverse agg-step */
   const char *zName;   /* SQL name of the function. */
   union {
     FuncDef *pHash;      /* Next with a different name but the same hash */
@@ -16183,6 +16410,8 @@ struct FuncDestructor {
                                     ** single query - might change over time */
 #define SQLITE_FUNC_AFFINITY 0x4000 /* Built-in affinity() function */
 #define SQLITE_FUNC_OFFSET   0x8000 /* Built-in sqlite_offset() function */
+#define SQLITE_FUNC_WINDOW  0x10000 /* Built-in window-only function */
+#define SQLITE_FUNC_WINDOW_SIZE  0x20000  /* Requires partition size as arg. */
 
 /*
 ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
@@ -16217,6 +16446,12 @@ struct FuncDestructor {
 **     are interpreted in the same way as the first 4 parameters to
 **     FUNCTION().
 **
+**   WFUNCTION(zName, nArg, iArg, xStep, xFinal, xValue, xInverse)
+**     Used to create an aggregate function definition implemented by
+**     the C functions xStep and xFinal. The first four parameters
+**     are interpreted in the same way as the first 4 parameters to
+**     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
@@ -16227,31 +16462,35 @@ struct FuncDestructor {
 */
 #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} }
+   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
 #define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \
   {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
-   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
+   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
 #define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \
   {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8, \
-   0, 0, xFunc, 0, #zName, {0} }
+   0, 0, xFunc, 0, 0, 0, #zName, {0} }
 #define PURE_DATE(zName, nArg, iArg, bNC, xFunc) \
   {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \
-   (void*)&sqlite3Config, 0, xFunc, 0, #zName, {0} }
+   (void*)&sqlite3Config, 0, xFunc, 0, 0, 0, #zName, {0} }
 #define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \
   {nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\
-   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
+   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
 #define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
   {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
-   pArg, 0, xFunc, 0, #zName, }
+   pArg, 0, xFunc, 0, 0, 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) \
+   (void *)arg, 0, likeFunc, 0, 0, 0, #zName, {0} }
+#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal, xValue) \
   {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \
-   SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}}
+   SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xValue,0,#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}}
+   SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xFinal,0,#zName, {0}}
+
+#define WAGGREGATE(zName, nArg, arg, nc, xStep, xFinal, xValue, xInverse, f) \
+  {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|f, \
+   SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xValue,xInverse,#zName, {0}}
 
 /*
 ** All current savepoints are stored in a linked list starting at
@@ -16737,6 +16976,7 @@ struct Index {
   tRowcnt *aiRowEst;       /* Non-logarithmic stat1 data for this index */
   tRowcnt nRowEst0;        /* Non-logarithmic number of rows in the index */
 #endif
+  Bitmask colNotIdxed;     /* 0 for unindexed columns in pTab */
 };
 
 /*
@@ -16775,9 +17015,11 @@ struct IndexSample {
 ** 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.
+** The memory that "z" points to is owned by other objects.  Take care
+** that the owner of the "z" string does not deallocate the string before
+** the Token goes out of scope!  Very often, the "z" points to some place
+** in the middle of the Parse.zSql text.  But it might also point to a
+** static string.
 */
 struct Token {
   const char *z;     /* Text of the token.  Not NULL-terminated! */
@@ -16952,6 +17194,9 @@ struct Expr {
   AggInfo *pAggInfo;     /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
   Table *pTab;           /* Table for TK_COLUMN expressions.  Can be NULL
                          ** for a column of an index on an expression */
+#ifndef SQLITE_OMIT_WINDOWFUNC
+  Window *pWin;          /* Window definition for window functions */
+#endif
 };
 
 /*
@@ -16960,7 +17205,7 @@ struct Expr {
 #define EP_FromJoin  0x000001 /* Originates in ON/USING clause of outer join */
 #define EP_Agg       0x000002 /* Contains one or more aggregate functions */
 #define EP_HasFunc   0x000004 /* Contains one or more functions of any kind */
-                  /* 0x000008 // available for use */
+#define EP_FixedCol  0x000008 /* TK_Column with a known fixed value */
 #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 "..." */
@@ -17082,31 +17327,6 @@ struct IdList {
   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
@@ -17238,6 +17458,7 @@ struct NameContext {
   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 */
+  Select *pWinSelect;  /* SELECT statement for any window functions */
 };
 
 /*
@@ -17260,6 +17481,7 @@ struct NameContext {
 #define NC_UUpsert   0x0200  /* True if uNC.pUpsert is used */
 #define NC_MinMaxAgg 0x1000  /* min/max aggregates seen.  See note above */
 #define NC_Complex   0x2000  /* True if a function or subquery seen */
+#define NC_AllowWin  0x4000  /* Window functions are allowed here */
 
 /*
 ** An instance of the following object describes a single ON CONFLICT
@@ -17314,9 +17536,7 @@ struct Select {
   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
+  u32 selId;             /* Unique identifier number for this SELECT */
   int addrOpenEphm[2];   /* OP_OpenEphem opcodes related to this select */
   SrcList *pSrc;         /* The FROM clause */
   Expr *pWhere;          /* The WHERE clause */
@@ -17327,6 +17547,10 @@ struct Select {
   Select *pNext;         /* Next select to the left in a compound */
   Expr *pLimit;          /* LIMIT expression. NULL means not used. */
   With *pWith;           /* WITH clause attached to this select. Or NULL. */
+#ifndef SQLITE_OMIT_WINDOWFUNC
+  Window *pWin;          /* List of window functions */
+  Window *pWinDefn;      /* List of named window definitions */
+#endif
 };
 
 /*
@@ -17470,13 +17694,6 @@ struct AutoincInfo {
   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
@@ -17552,7 +17769,6 @@ struct Parse {
   u8 hasCompound;      /* Need to invoke convertCompoundSelectToSubquery() */
   u8 okConstFactor;    /* OK to factor out constants */
   u8 disableLookaside; /* Number of times lookaside has been disabled */
-  u8 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 */
@@ -17562,8 +17778,6 @@ struct Parse {
   int szOpAlloc;       /* Bytes of memory space allocated for Vdbe.aOp[] */
   int iSelfTab;        /* Table associated with an index on expr, or negative
                        ** of the base register during check-constraint eval */
-  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 */
@@ -17573,9 +17787,7 @@ struct Parse {
   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 */
-#endif
+  int nSelect;         /* Number of SELECT stmts. Counter for Select.selId */
 #ifndef SQLITE_OMIT_SHARED_CACHE
   int nTableLock;        /* Number of locks in aTableLock */
   TableLock *aTableLock; /* Required table locks for shared-cache mode */
@@ -17595,17 +17807,9 @@ struct Parse {
   ** 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).
+  ** determined by offsetof(Parse,aTempReg).
   **************************************************************************/
 
-  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 */
 
@@ -17620,8 +17824,10 @@ struct Parse {
   ynVar nVar;               /* Number of '?' variables seen in the SQL so far */
   u8 iPkSortOrder;          /* ASC or DESC for INTEGER PRIMARY KEY */
   u8 explain;               /* True if the EXPLAIN flag is found on the query */
+#if !(defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_OMIT_ALTERTABLE))
+  u8 eParseMode;            /* PARSE_MODE_XXX constant */
+#endif
 #ifndef SQLITE_OMIT_VIRTUALTABLE
-  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 */
@@ -17632,6 +17838,7 @@ struct Parse {
   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 */
+  Index *pNewIndex;         /* An index being constructed by CREATE INDEX */
   Trigger *pNewTrigger;     /* Trigger under construct by a CREATE TRIGGER */
   const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
 #ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -17642,12 +17849,20 @@ struct Parse {
   TriggerPrg *pTriggerPrg;  /* Linked list of coded triggers */
   With *pWith;              /* Current WITH clause, or NULL */
   With *pWithToFree;        /* Free this WITH object at the end of the parse */
+#ifndef SQLITE_OMIT_ALTERTABLE
+  RenameToken *pRename;     /* Tokens subject to renaming by ALTER TABLE */
+#endif
 };
 
+#define PARSE_MODE_NORMAL        0
+#define PARSE_MODE_DECLARE_VTAB  1
+#define PARSE_MODE_RENAME_COLUMN 2
+#define PARSE_MODE_RENAME_TABLE  3
+
 /*
 ** Sizes and pointers of various parts of the Parse object.
 */
-#define PARSE_HDR_SZ offsetof(Parse,aColCache) /* Recursive part w/o aColCache*/
+#define PARSE_HDR_SZ offsetof(Parse,aTempReg) /* 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 */
@@ -17658,7 +17873,19 @@ struct Parse {
 #ifdef SQLITE_OMIT_VIRTUALTABLE
   #define IN_DECLARE_VTAB 0
 #else
-  #define IN_DECLARE_VTAB (pParse->declareVtab)
+  #define IN_DECLARE_VTAB (pParse->eParseMode==PARSE_MODE_DECLARE_VTAB)
+#endif
+
+#if defined(SQLITE_OMIT_ALTERTABLE)
+  #define IN_RENAME_OBJECT 0
+#else
+  #define IN_RENAME_OBJECT (pParse->eParseMode>=PARSE_MODE_RENAME_COLUMN)
+#endif
+
+#if defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_OMIT_ALTERTABLE)
+  #define IN_SPECIAL_PARSE 0
+#else
+  #define IN_SPECIAL_PARSE (pParse->eParseMode!=PARSE_MODE_NORMAL)
 #endif
 
 /*
@@ -17837,8 +18064,14 @@ typedef struct {
   char **pzErrMsg;    /* Error message stored here */
   int iDb;            /* 0 for main database.  1 for TEMP, 2.. for ATTACHed */
   int rc;             /* Result code stored here */
+  u32 mInitFlags;     /* Flags controlling error messages */
 } InitData;
 
+/*
+** Allowed values for mInitFlags
+*/
+#define INITFLAG_AlterTable   0x0001  /* This is a reparse after ALTER TABLE */
+
 /*
 ** Structure containing global configuration data for the SQLite library.
 **
@@ -17889,7 +18122,7 @@ struct Sqlite3Config {
   /* 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 (*xVdbeBranch)(void*,unsigned iSrcLine,u8 eThis,u8 eMx);  /* Callback */
   void *pVdbeBranchArg;                                     /* 1st argument */
 #endif
 #ifndef SQLITE_UNTESTABLE
@@ -17940,6 +18173,9 @@ struct Walker {
     struct IdxExprTrans *pIdxTrans;           /* Convert idxed expr to column */
     ExprList *pGroupBy;                       /* GROUP BY clause */
     Select *pSelect;                          /* HAVING to WHERE clause ctx */
+    struct WindowRewrite *pRewrite;           /* Window rewrite context */
+    struct WhereConst *pConst;                /* WHERE clause constants */
+    struct RenameCtx *pRename;                /* RENAME COLUMN context */
   } u;
 };
 
@@ -17990,6 +18226,68 @@ struct TreeView {
 };
 #endif /* SQLITE_DEBUG */
 
+/*
+** This object is used in varioius ways, all related to window functions
+**
+**   (1) A single instance of this structure is attached to the
+**       the Expr.pWin field for each window function in an expression tree.
+**       This object holds the information contained in the OVER clause,
+**       plus additional fields used during code generation.
+**
+**   (2) All window functions in a single SELECT form a linked-list
+**       attached to Select.pWin.  The Window.pFunc and Window.pExpr
+**       fields point back to the expression that is the window function.
+**
+**   (3) The terms of the WINDOW clause of a SELECT are instances of this
+**       object on a linked list attached to Select.pWinDefn.
+**
+** The uses (1) and (2) are really the same Window object that just happens
+** to be accessible in two different ways.  Use (3) is are separate objects.
+*/
+struct Window {
+  char *zName;            /* Name of window (may be NULL) */
+  ExprList *pPartition;   /* PARTITION BY clause */
+  ExprList *pOrderBy;     /* ORDER BY clause */
+  u8 eType;               /* TK_RANGE or TK_ROWS */
+  u8 eStart;              /* UNBOUNDED, CURRENT, PRECEDING or FOLLOWING */
+  u8 eEnd;                /* UNBOUNDED, CURRENT, PRECEDING or FOLLOWING */
+  Expr *pStart;           /* Expression for "<expr> PRECEDING" */
+  Expr *pEnd;             /* Expression for "<expr> FOLLOWING" */
+  Window *pNextWin;       /* Next window function belonging to this SELECT */
+  Expr *pFilter;          /* The FILTER expression */
+  FuncDef *pFunc;         /* The function */
+  int iEphCsr;            /* Partition buffer or Peer buffer */
+  int regAccum;
+  int regResult;
+  int csrApp;             /* Function cursor (used by min/max) */
+  int regApp;             /* Function register (also used by min/max) */
+  int regPart;            /* First in a set of registers holding PARTITION BY
+                          ** and ORDER BY values for the window */
+  Expr *pOwner;           /* Expression object this window is attached to */
+  int nBufferCol;         /* Number of columns in buffer table */
+  int iArgCol;            /* Offset of first argument for this function */
+};
+
+#ifndef SQLITE_OMIT_WINDOWFUNC
+SQLITE_PRIVATE void sqlite3WindowDelete(sqlite3*, Window*);
+SQLITE_PRIVATE void sqlite3WindowListDelete(sqlite3 *db, Window *p);
+SQLITE_PRIVATE Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*);
+SQLITE_PRIVATE void sqlite3WindowAttach(Parse*, Expr*, Window*);
+SQLITE_PRIVATE int sqlite3WindowCompare(Parse*, Window*, Window*);
+SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse*, Window*);
+SQLITE_PRIVATE void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int);
+SQLITE_PRIVATE int sqlite3WindowRewrite(Parse*, Select*);
+SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse*, struct SrcList_item*);
+SQLITE_PRIVATE void sqlite3WindowUpdate(Parse*, Window*, Window*, FuncDef*);
+SQLITE_PRIVATE Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p);
+SQLITE_PRIVATE Window *sqlite3WindowListDup(sqlite3 *db, Window *p);
+SQLITE_PRIVATE void sqlite3WindowFunctions(void);
+#else
+# define sqlite3WindowDelete(a,b)
+# define sqlite3WindowFunctions()
+# define sqlite3WindowAttach(a,b,c)
+#endif
+
 /*
 ** 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.
@@ -18077,9 +18375,7 @@ SQLITE_PRIVATE   int sqlite3CorruptPgnoError(int,Pgno);
 # 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
@@ -18204,6 +18500,10 @@ SQLITE_PRIVATE   void sqlite3TreeViewBareExprList(TreeView*, const ExprList*, co
 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);
+#ifndef SQLITE_OMIT_WINDOWFUNC
+SQLITE_PRIVATE   void sqlite3TreeViewWindow(TreeView*, const Window*, u8);
+SQLITE_PRIVATE   void sqlite3TreeViewWinFunc(TreeView*, const Window*, u8);
+#endif
 #endif
 
 
@@ -18228,7 +18528,7 @@ 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 Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*, int);
 SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32);
 SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*);
 SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
@@ -18240,6 +18540,7 @@ 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 int sqlite3InitOne(sqlite3*, int, char**, u32);
 SQLITE_PRIVATE void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
 #ifndef SQLITE_OMIT_VIRTUALTABLE
 SQLITE_PRIVATE Module *sqlite3PragmaVtabRegister(sqlite3*,const char *zName);
@@ -18289,8 +18590,9 @@ SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec*);
 SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int,int*);
 #endif
 
-SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int);
-SQLITE_PRIVATE void sqlite3RowSetClear(RowSet*);
+SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3*);
+SQLITE_PRIVATE void sqlite3RowSetDelete(void*);
+SQLITE_PRIVATE void sqlite3RowSetClear(void*);
 SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet*, i64);
 SQLITE_PRIVATE int sqlite3RowSetTest(RowSet*, int iBatch, i64);
 SQLITE_PRIVATE int sqlite3RowSetNext(RowSet*, i64*);
@@ -18309,6 +18611,7 @@ SQLITE_PRIVATE   int sqlite3DbMaskAllZero(yDbMask);
 SQLITE_PRIVATE void sqlite3DropTable(Parse*, SrcList*, int, int);
 SQLITE_PRIVATE void sqlite3CodeDropTable(Parse*, Table*, int, int);
 SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3*, Table*);
+SQLITE_PRIVATE void sqlite3FreeIndex(sqlite3*, Index*);
 #ifndef SQLITE_OMIT_AUTOINCREMENT
 SQLITE_PRIVATE   void sqlite3AutoincrementBegin(Parse *pParse);
 SQLITE_PRIVATE   void sqlite3AutoincrementEnd(Parse *pParse);
@@ -18318,7 +18621,7 @@ SQLITE_PRIVATE   void sqlite3AutoincrementEnd(Parse *pParse);
 #endif
 SQLITE_PRIVATE void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int, Upsert*);
 SQLITE_PRIVATE void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*);
-SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*);
+SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse*, 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*);
@@ -18353,7 +18656,7 @@ 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 sqlite3WhereOrderByLimitOptLabel(WhereInfo*);
 SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo*);
 SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo*);
 SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo*);
@@ -18363,15 +18666,8 @@ SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo*, int*);
 #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);
@@ -18459,11 +18755,6 @@ 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);
@@ -18492,12 +18783,12 @@ SQLITE_PRIVATE   void sqlite3CodeRowTriggerDirect(Parse *, Trigger *, Table *, i
 SQLITE_PRIVATE   void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*);
 SQLITE_PRIVATE   TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*,
                                         const char*,const char*);
-SQLITE_PRIVATE   TriggerStep *sqlite3TriggerInsertStep(sqlite3*,Token*, IdList*,
+SQLITE_PRIVATE   TriggerStep *sqlite3TriggerInsertStep(Parse*,Token*, IdList*,
                                         Select*,u8,Upsert*,
                                         const char*,const char*);
-SQLITE_PRIVATE   TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, u8,
+SQLITE_PRIVATE   TriggerStep *sqlite3TriggerUpdateStep(Parse*,Token*,ExprList*, Expr*, u8,
                                         const char*,const char*);
-SQLITE_PRIVATE   TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*,
+SQLITE_PRIVATE   TriggerStep *sqlite3TriggerDeleteStep(Parse*,Token*, Expr*,
                                         const char*,const char*);
 SQLITE_PRIVATE   void sqlite3DeleteTrigger(sqlite3*, Trigger*);
 SQLITE_PRIVATE   void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
@@ -18612,6 +18903,7 @@ SQLITE_PRIVATE int sqlite3MemdbInit(void);
 SQLITE_PRIVATE const char *sqlite3ErrStr(int);
 SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse);
 SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
+SQLITE_PRIVATE int sqlite3IsBinary(const CollSeq*);
 SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
 SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
 SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr);
@@ -18664,9 +18956,10 @@ 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 void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*);
 SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *);
 SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...);
-SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*);
+SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*, int);
 SQLITE_PRIVATE int sqlite3CodeSubselect(Parse*, Expr *, int, int);
 SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*);
 SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p);
@@ -18679,6 +18972,10 @@ SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const
 SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
 SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *);
 SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
+SQLITE_PRIVATE void *sqlite3RenameTokenMap(Parse*, void*, Token*);
+SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse*, void *pTo, void *pFrom);
+SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse*, Expr*);
+SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse*, ExprList*);
 SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
 SQLITE_PRIVATE char sqlite3AffinityType(const char*, Column*);
 SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*);
@@ -18697,12 +18994,17 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3*,int,int);
 SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo*);
 SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoRef(KeyInfo*);
 SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*);
+SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoFromExprList(Parse*, ExprList*, int, int);
+
 #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*),
+  void (*)(sqlite3_context*,int,sqlite3_value **), 
+  void (*)(sqlite3_context*),
+  void (*)(sqlite3_context*),
+  void (*)(sqlite3_context*,int,sqlite3_value **), 
   FuncDestructor *pDestructor
 );
 SQLITE_PRIVATE void sqlite3NoopDestructor(void*);
@@ -18743,6 +19045,7 @@ SQLITE_PRIVATE   void *sqlite3ParserAlloc(void*(*)(u64), Parse*);
 SQLITE_PRIVATE   void sqlite3ParserFree(void*, void(*)(void*));
 #endif
 SQLITE_PRIVATE void sqlite3Parser(void*, int, Token);
+SQLITE_PRIVATE int sqlite3ParserFallback(int);
 #ifdef YYTRACKMAXSTACKDEPTH
 SQLITE_PRIVATE   int sqlite3ParserStackPeak(void*);
 #endif
@@ -19443,6 +19746,7 @@ struct VdbeCursor {
   Bool isEphemeral:1;     /* True for an ephemeral table */
   Bool useRandomRowid:1;  /* Generate new record numbers semi-randomly */
   Bool isOrdered:1;       /* True if the table is not BTREE_UNORDERED */
+  Bool seekHit:1;         /* See the OP_SeekHit and OP_IfNoHope opcodes */
   Btree *pBtx;            /* Separate file holding temporary table */
   i64 seqCount;           /* Sequence counter */
   int *aAltMap;           /* Mapping from table to index column numbers */
@@ -19526,6 +19830,9 @@ struct VdbeFrame {
   void *token;            /* Copy of SubProgram.token */
   i64 lastRowid;          /* Last insert rowid (sqlite3.lastRowid) */
   AuxData *pAuxData;      /* Linked list of auxdata allocations */
+#if SQLITE_DEBUG
+  u32 iFrameMagic;        /* magic number for sanity checking */
+#endif
   int nCursor;            /* Number of entries in apCsr */
   int pc;                 /* Program Counter in parent (calling) frame */
   int nOp;                /* Size of aOp array */
@@ -19536,6 +19843,13 @@ struct VdbeFrame {
   int nDbChange;          /* Value of db->nChange */
 };
 
+/* Magic number for sanity checking on VdbeFrame objects */
+#define SQLITE_FRAME_MAGIC 0x879fb71e
+
+/*
+** Return a pointer to the array of registers allocated for use
+** by a VdbeFrame.
+*/
 #define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
 
 /*
@@ -19550,8 +19864,6 @@ struct sqlite3_value {
     int nZero;          /* Extra zero bytes when MEM_Zero and MEM_Blob set */
     const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */
     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 */
@@ -19566,7 +19878,7 @@ struct sqlite3_value {
   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 */
+  u16 mScopyFlags;    /* flags value immediately after the shallow copy */
 #endif
 };
 
@@ -19595,8 +19907,8 @@ struct sqlite3_value {
 #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 */
+/* Available          0x0020   */
+/* Available          0x0040   */
 #define MEM_Undefined 0x0080   /* Value is undefined */
 #define MEM_Cleared   0x0100   /* NULL set by OP_Null, not from data */
 #define MEM_TypeMask  0xc1ff   /* Mask of type bits */
@@ -19623,7 +19935,7 @@ struct sqlite3_value {
 ** that needs to be deallocated to avoid a leak.
 */
 #define VdbeMemDynamic(X)  \
-  (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0)
+  (((X)->flags&(MEM_Agg|MEM_Dyn))!=0)
 
 /*
 ** Clear any existing type flags from a Mem and replace them with f
@@ -19743,9 +20055,9 @@ struct Vdbe {
   u8 errorAction;         /* Recovery action to do in case of an error */
   u8 minWriteFileFormat;  /* Minimum file format for writable database files */
   u8 prepFlags;           /* SQLITE_PREPARE_* flags */
-  bft expired:1;          /* True if the VM needs to be recompiled */
-  bft doingRerun:1;       /* True if rerunning after an auto-reprepare */
+  bft expired:2;          /* 1: recompile VM immediately  2: when convenient */
   bft explain:2;          /* True if EXPLAIN present on SQL command */
+  bft doingRerun:1;       /* True if rerunning after an auto-reprepare */
   bft changeCntOn:1;      /* True to update the change-counter */
   bft runOnlyOnce:1;      /* Automatically expire on reset */
   bft usesStmtJournal:1;  /* True if uses a statement journal */
@@ -19806,9 +20118,6 @@ 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*);
@@ -19839,7 +20148,10 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetPointer(Mem*, void*, const char*, void(*)(v
 SQLITE_PRIVATE void sqlite3VdbeMemInit(Mem*,sqlite3*,u16);
 SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem*);
 SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem*,int);
-SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem*);
+#ifdef SQLITE_DEBUG
+SQLITE_PRIVATE int sqlite3VdbeMemIsRowSet(const Mem*);
+#endif
+SQLITE_PRIVATE int sqlite3VdbeMemSetRowSet(Mem*);
 SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem*);
 SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem*, u8, u8);
 SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem*);
@@ -19853,11 +20165,18 @@ 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*);
+#ifndef SQLITE_OMIT_WINDOWFUNC
+SQLITE_PRIVATE int sqlite3VdbeMemAggValue(Mem*, Mem*, FuncDef*);
+#endif
 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*);
+#ifdef SQLITE_DEBUG
+SQLITE_PRIVATE int sqlite3VdbeFrameIsValid(VdbeFrame*);
+#endif
+SQLITE_PRIVATE void sqlite3VdbeFrameMemDel(void*);      /* Destructor on Mem */
+SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*); /* Actually deletes the Frame */
 SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *);
 #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
 SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int);
@@ -21955,9 +22274,12 @@ SQLITE_API int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
 ** 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);
+  MUTEX_LOGIC(sqlite3_mutex *mutex;)
+#ifndef SQLITE_OMIT_AUTOINIT
+  int rc = sqlite3_initialize();
+  if( rc ) return rc;
 #endif
+  MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
   sqlite3_mutex_enter(mutex);
   vfsUnlink(pVfs);
   sqlite3_mutex_leave(mutex);
@@ -27288,7 +27610,12 @@ SQLITE_API void sqlite3_str_vappendf(
         if( bufpt==0 ){
           bufpt = "";
         }else if( xtype==etDYNSTRING ){
-          if( pAccum->nChar==0 && pAccum->mxAlloc && width==0 && precision<0 ){
+          if( pAccum->nChar==0
+           && pAccum->mxAlloc
+           && width==0
+           && precision<0
+           && pAccum->accError==0
+          ){
             /* Special optimization for sqlite3_mprintf("%z..."):
             ** Extend an existing memory allocation rather than creating
             ** a new one. */
@@ -27986,21 +28313,13 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
     sqlite3TreeViewPush(pView, 1);
   }
   do{
-#if SELECTTRACE_ENABLED
     sqlite3TreeViewLine(pView,
-      "SELECT%s%s (%s/%p) selFlags=0x%x nSelectRow=%d",
+      "SELECT%s%s (%u/%p) selFlags=0x%x nSelectRow=%d",
       ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
       ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""),
-      p->zSelName, p, p->selFlags,
-      (int)p->nSelectRow
-    );
-#else
-    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,
+      p->selId, p, p->selFlags,
       (int)p->nSelectRow
     );
-#endif
     if( cnt++ ) sqlite3TreeViewPop(pView);
     if( p->pPrior ){
       n = 1000;
@@ -28012,8 +28331,23 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
       if( p->pHaving ) n++;
       if( p->pOrderBy ) n++;
       if( p->pLimit ) n++;
+#ifndef SQLITE_OMIT_WINDOWFUNC
+      if( p->pWin ) n++;
+      if( p->pWinDefn ) n++;
+#endif
     }
     sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set");
+#ifndef SQLITE_OMIT_WINDOWFUNC
+    if( p->pWin ){
+      Window *pX;
+      pView = sqlite3TreeViewPush(pView, (n--)>0);
+      sqlite3TreeViewLine(pView, "window-functions");
+      for(pX=p->pWin; pX; pX=pX->pNextWin){
+        sqlite3TreeViewWinFunc(pView, pX, pX->pNextWin!=0);
+      }
+      sqlite3TreeViewPop(pView);
+    }
+#endif
     if( p->pSrc && p->pSrc->nSrc ){
       int i;
       pView = sqlite3TreeViewPush(pView, (n--)>0);
@@ -28063,6 +28397,16 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
       sqlite3TreeViewExpr(pView, p->pHaving, 0);
       sqlite3TreeViewPop(pView);
     }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+    if( p->pWinDefn ){
+      Window *pX;
+      sqlite3TreeViewItem(pView, "WINDOW", (n--)>0);
+      for(pX=p->pWinDefn; pX; pX=pX->pNextWin){
+        sqlite3TreeViewWindow(pView, pX, pX->pNextWin!=0);
+      }
+      sqlite3TreeViewPop(pView);
+    }
+#endif
     if( p->pOrderBy ){
       sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY");
     }
@@ -28090,6 +28434,83 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
   sqlite3TreeViewPop(pView);
 }
 
+#ifndef SQLITE_OMIT_WINDOWFUNC
+/*
+** Generate a description of starting or stopping bounds
+*/
+SQLITE_PRIVATE void sqlite3TreeViewBound(
+  TreeView *pView,        /* View context */
+  u8 eBound,              /* UNBOUNDED, CURRENT, PRECEDING, FOLLOWING */
+  Expr *pExpr,            /* Value for PRECEDING or FOLLOWING */
+  u8 moreToFollow         /* True if more to follow */
+){
+  switch( eBound ){
+    case TK_UNBOUNDED: {
+      sqlite3TreeViewItem(pView, "UNBOUNDED", moreToFollow);
+      sqlite3TreeViewPop(pView);
+      break;
+    }
+    case TK_CURRENT: {
+      sqlite3TreeViewItem(pView, "CURRENT", moreToFollow);
+      sqlite3TreeViewPop(pView);
+      break;
+    }
+    case TK_PRECEDING: {
+      sqlite3TreeViewItem(pView, "PRECEDING", moreToFollow);
+      sqlite3TreeViewExpr(pView, pExpr, 0);
+      sqlite3TreeViewPop(pView);
+      break;
+    }
+    case TK_FOLLOWING: {
+      sqlite3TreeViewItem(pView, "FOLLOWING", moreToFollow);
+      sqlite3TreeViewExpr(pView, pExpr, 0);
+      sqlite3TreeViewPop(pView);
+      break;
+    }
+  }
+}
+#endif /* SQLITE_OMIT_WINDOWFUNC */
+
+#ifndef SQLITE_OMIT_WINDOWFUNC
+/*
+** Generate a human-readable explanation for a Window object
+*/
+SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){
+  pView = sqlite3TreeViewPush(pView, more);
+  if( pWin->zName ){
+    sqlite3TreeViewLine(pView, "OVER %s", pWin->zName);
+  }else{
+    sqlite3TreeViewLine(pView, "OVER");
+  }
+  if( pWin->pPartition ){
+    sqlite3TreeViewExprList(pView, pWin->pPartition, 1, "PARTITION-BY");
+  }
+  if( pWin->pOrderBy ){
+    sqlite3TreeViewExprList(pView, pWin->pOrderBy, 1, "ORDER-BY");
+  }
+  if( pWin->eType ){
+    sqlite3TreeViewItem(pView, pWin->eType==TK_RANGE ? "RANGE" : "ROWS", 0);
+    sqlite3TreeViewBound(pView, pWin->eStart, pWin->pStart, 1);
+    sqlite3TreeViewBound(pView, pWin->eEnd, pWin->pEnd, 0);
+    sqlite3TreeViewPop(pView);
+  }
+  sqlite3TreeViewPop(pView);
+}
+#endif /* SQLITE_OMIT_WINDOWFUNC */
+
+#ifndef SQLITE_OMIT_WINDOWFUNC
+/*
+** Generate a human-readable explanation for a Window Function object
+*/
+SQLITE_PRIVATE void sqlite3TreeViewWinFunc(TreeView *pView, const Window *pWin, u8 more){
+  pView = sqlite3TreeViewPush(pView, more);
+  sqlite3TreeViewLine(pView, "WINFUNC %s(%d)",
+                       pWin->pFunc->zName, pWin->pFunc->nArg);
+  sqlite3TreeViewWindow(pView, pWin, 0);
+  sqlite3TreeViewPop(pView);
+}
+#endif /* SQLITE_OMIT_WINDOWFUNC */
+
 /*
 ** Generate a human-readable explanation of an expression tree.
 */
@@ -28127,6 +28548,9 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
         sqlite3TreeViewLine(pView, "{%d:%d}%s",
                              pExpr->iTable, pExpr->iColumn, zFlgs);
       }
+      if( ExprHasProperty(pExpr, EP_FixedCol) ){
+        sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
+      }
       break;
     }
     case TK_INTEGER: {
@@ -28240,10 +28664,17 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
     case TK_AGG_FUNCTION:
     case TK_FUNCTION: {
       ExprList *pFarg;       /* List of function arguments */
+      Window *pWin;
       if( ExprHasProperty(pExpr, EP_TokenOnly) ){
         pFarg = 0;
+        pWin = 0;
       }else{
         pFarg = pExpr->x.pList;
+#ifndef SQLITE_OMIT_WINDOWFUNC
+        pWin = pExpr->pWin;
+#else
+        pWin = 0;
+#endif 
       }
       if( pExpr->op==TK_AGG_FUNCTION ){
         sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q",
@@ -28252,8 +28683,13 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
         sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken);
       }
       if( pFarg ){
-        sqlite3TreeViewExprList(pView, pFarg, 0, 0);
+        sqlite3TreeViewExprList(pView, pFarg, pWin!=0, 0);
       }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+      if( pWin ){
+        sqlite3TreeViewWindow(pView, pWin, 0);
+      }
+#endif
       break;
     }
 #ifndef SQLITE_OMIT_SUBQUERY
@@ -31285,52 +31721,52 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
     /*   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(""),
+    /*   4 */ "Prev"             OpHelp(""),
+    /*   5 */ "Next"             OpHelp(""),
+    /*   6 */ "Checkpoint"       OpHelp(""),
+    /*   7 */ "JournalMode"      OpHelp(""),
+    /*   8 */ "Vacuum"           OpHelp(""),
+    /*   9 */ "VFilter"          OpHelp("iplan=r[P3] zplan='P4'"),
+    /*  10 */ "VUpdate"          OpHelp("data=r[P3@P2]"),
+    /*  11 */ "Goto"             OpHelp(""),
+    /*  12 */ "Gosub"            OpHelp(""),
+    /*  13 */ "InitCoroutine"    OpHelp(""),
+    /*  14 */ "Yield"            OpHelp(""),
+    /*  15 */ "MustBeInt"        OpHelp(""),
+    /*  16 */ "Jump"             OpHelp(""),
+    /*  17 */ "Once"             OpHelp(""),
+    /*  18 */ "If"               OpHelp(""),
     /*  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)"),
+    /*  20 */ "IfNot"            OpHelp(""),
+    /*  21 */ "IfNullRow"        OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"),
+    /*  22 */ "SeekLT"           OpHelp("key=r[P3@P4]"),
+    /*  23 */ "SeekLE"           OpHelp("key=r[P3@P4]"),
+    /*  24 */ "SeekGE"           OpHelp("key=r[P3@P4]"),
+    /*  25 */ "SeekGT"           OpHelp("key=r[P3@P4]"),
+    /*  26 */ "IfNoHope"         OpHelp("key=r[P3@P4]"),
+    /*  27 */ "NoConflict"       OpHelp("key=r[P3@P4]"),
+    /*  28 */ "NotFound"         OpHelp("key=r[P3@P4]"),
+    /*  29 */ "Found"            OpHelp("key=r[P3@P4]"),
+    /*  30 */ "SeekRowid"        OpHelp("intkey=r[P3]"),
+    /*  31 */ "NotExists"        OpHelp("intkey=r[P3]"),
+    /*  32 */ "Last"             OpHelp(""),
+    /*  33 */ "IfSmaller"        OpHelp(""),
+    /*  34 */ "SorterSort"       OpHelp(""),
+    /*  35 */ "Sort"             OpHelp(""),
+    /*  36 */ "Rewind"           OpHelp(""),
+    /*  37 */ "IdxLE"            OpHelp("key=r[P3@P4]"),
+    /*  38 */ "IdxGT"            OpHelp("key=r[P3@P4]"),
+    /*  39 */ "IdxLT"            OpHelp("key=r[P3@P4]"),
+    /*  40 */ "IdxGE"            OpHelp("key=r[P3@P4]"),
+    /*  41 */ "RowSetRead"       OpHelp("r[P3]=rowset(P1)"),
+    /*  42 */ "RowSetTest"       OpHelp("if r[P3] in rowset(P1) goto P2"),
     /*  43 */ "Or"               OpHelp("r[P3]=(r[P1] || r[P2])"),
     /*  44 */ "And"              OpHelp("r[P3]=(r[P1] && r[P2])"),
-    /*  45 */ "RowSetTest"       OpHelp("if r[P3] in rowset(P1) goto P2"),
-    /*  46 */ "Program"          OpHelp(""),
-    /*  47 */ "FkIfZero"         OpHelp("if fkctr[P1]==0 goto P2"),
-    /*  48 */ "IfPos"            OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
-    /*  49 */ "IfNotZero"        OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
+    /*  45 */ "Program"          OpHelp(""),
+    /*  46 */ "FkIfZero"         OpHelp("if fkctr[P1]==0 goto P2"),
+    /*  47 */ "IfPos"            OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
+    /*  48 */ "IfNotZero"        OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
+    /*  49 */ "DecrJumpZero"     OpHelp("if (--r[P1])==0 goto P2"),
     /*  50 */ "IsNull"           OpHelp("if r[P1]==NULL goto P2"),
     /*  51 */ "NotNull"          OpHelp("if r[P1]!=NULL goto P2"),
     /*  52 */ "Ne"               OpHelp("IF r[P3]!=r[P1]"),
@@ -31340,119 +31776,121 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
     /*  56 */ "Lt"               OpHelp("IF r[P3]<r[P1]"),
     /*  57 */ "Ge"               OpHelp("IF r[P3]>=r[P1]"),
     /*  58 */ "ElseNotEq"        OpHelp(""),
-    /*  59 */ "DecrJumpZero"     OpHelp("if (--r[P1])==0 goto P2"),
-    /*  60 */ "IncrVacuum"       OpHelp(""),
-    /*  61 */ "VNext"            OpHelp(""),
-    /*  62 */ "Init"             OpHelp("Start at P2"),
-    /*  63 */ "Return"           OpHelp(""),
-    /*  64 */ "EndCoroutine"     OpHelp(""),
-    /*  65 */ "HaltIfNull"       OpHelp("if r[P3]=null halt"),
-    /*  66 */ "Halt"             OpHelp(""),
-    /*  67 */ "Integer"          OpHelp("r[P2]=P1"),
-    /*  68 */ "Int64"            OpHelp("r[P2]=P4"),
-    /*  69 */ "String"           OpHelp("r[P2]='P4' (len=P1)"),
-    /*  70 */ "Null"             OpHelp("r[P2..P3]=NULL"),
-    /*  71 */ "SoftNull"         OpHelp("r[P1]=NULL"),
-    /*  72 */ "Blob"             OpHelp("r[P2]=P4 (len=P1)"),
-    /*  73 */ "Variable"         OpHelp("r[P2]=parameter(P1,P4)"),
-    /*  74 */ "Move"             OpHelp("r[P2@P3]=r[P1@P3]"),
-    /*  75 */ "Copy"             OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
-    /*  76 */ "SCopy"            OpHelp("r[P2]=r[P1]"),
-    /*  77 */ "IntCopy"          OpHelp("r[P2]=r[P1]"),
-    /*  78 */ "ResultRow"        OpHelp("output=r[P1@P2]"),
-    /*  79 */ "CollSeq"          OpHelp(""),
-    /*  80 */ "AddImm"           OpHelp("r[P1]=r[P1]+P2"),
-    /*  81 */ "RealAffinity"     OpHelp(""),
-    /*  82 */ "Cast"             OpHelp("affinity(r[P1])"),
-    /*  83 */ "Permutation"      OpHelp(""),
-    /*  84 */ "Compare"          OpHelp("r[P1@P3] <-> r[P2@P3]"),
-    /*  85 */ "BitAnd"           OpHelp("r[P3]=r[P1]&r[P2]"),
-    /*  86 */ "BitOr"            OpHelp("r[P3]=r[P1]|r[P2]"),
-    /*  87 */ "ShiftLeft"        OpHelp("r[P3]=r[P2]<<r[P1]"),
-    /*  88 */ "ShiftRight"       OpHelp("r[P3]=r[P2]>>r[P1]"),
-    /*  89 */ "Add"              OpHelp("r[P3]=r[P1]+r[P2]"),
-    /*  90 */ "Subtract"         OpHelp("r[P3]=r[P2]-r[P1]"),
-    /*  91 */ "Multiply"         OpHelp("r[P3]=r[P1]*r[P2]"),
-    /*  92 */ "Divide"           OpHelp("r[P3]=r[P2]/r[P1]"),
-    /*  93 */ "Remainder"        OpHelp("r[P3]=r[P2]%r[P1]"),
-    /*  94 */ "Concat"           OpHelp("r[P3]=r[P2]+r[P1]"),
-    /*  95 */ "IsTrue"           OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"),
-    /*  96 */ "BitNot"           OpHelp("r[P1]= ~r[P1]"),
-    /*  97 */ "Offset"           OpHelp("r[P3] = sqlite_offset(P1)"),
-    /*  98 */ "Column"           OpHelp("r[P3]=PX"),
-    /*  99 */ "String8"          OpHelp("r[P2]='P4'"),
-    /* 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 */ "SeekEnd"          OpHelp(""),
-    /* 128 */ "SorterInsert"     OpHelp("key=r[P2]"),
-    /* 129 */ "IdxInsert"        OpHelp("key=r[P2]"),
-    /* 130 */ "IdxDelete"        OpHelp("key=r[P2@P3]"),
-    /* 131 */ "DeferredSeek"     OpHelp("Move P3 to P1.rowid if needed"),
-    /* 132 */ "IdxRowid"         OpHelp("r[P2]=rowid"),
-    /* 133 */ "Destroy"          OpHelp(""),
-    /* 134 */ "Real"             OpHelp("r[P2]=P4"),
-    /* 135 */ "Clear"            OpHelp(""),
-    /* 136 */ "ResetSorter"      OpHelp(""),
-    /* 137 */ "CreateBtree"      OpHelp("r[P2]=root iDb=P1 flags=P3"),
-    /* 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 */ "PureFunc0"        OpHelp(""),
-    /* 164 */ "Function0"        OpHelp("r[P3]=func(r[P2@P5])"),
-    /* 165 */ "PureFunc"         OpHelp(""),
-    /* 166 */ "Function"         OpHelp("r[P3]=func(r[P2@P5])"),
-    /* 167 */ "Trace"            OpHelp(""),
-    /* 168 */ "CursorHint"       OpHelp(""),
-    /* 169 */ "Noop"             OpHelp(""),
-    /* 170 */ "Explain"          OpHelp(""),
-    /* 171 */ "Abortable"        OpHelp(""),
+    /*  59 */ "IncrVacuum"       OpHelp(""),
+    /*  60 */ "VNext"            OpHelp(""),
+    /*  61 */ "Init"             OpHelp("Start at P2"),
+    /*  62 */ "PureFunc0"        OpHelp(""),
+    /*  63 */ "Function0"        OpHelp("r[P3]=func(r[P2@P5])"),
+    /*  64 */ "PureFunc"         OpHelp(""),
+    /*  65 */ "Function"         OpHelp("r[P3]=func(r[P2@P5])"),
+    /*  66 */ "Return"           OpHelp(""),
+    /*  67 */ "EndCoroutine"     OpHelp(""),
+    /*  68 */ "HaltIfNull"       OpHelp("if r[P3]=null halt"),
+    /*  69 */ "Halt"             OpHelp(""),
+    /*  70 */ "Integer"          OpHelp("r[P2]=P1"),
+    /*  71 */ "Int64"            OpHelp("r[P2]=P4"),
+    /*  72 */ "String"           OpHelp("r[P2]='P4' (len=P1)"),
+    /*  73 */ "Null"             OpHelp("r[P2..P3]=NULL"),
+    /*  74 */ "SoftNull"         OpHelp("r[P1]=NULL"),
+    /*  75 */ "Blob"             OpHelp("r[P2]=P4 (len=P1)"),
+    /*  76 */ "Variable"         OpHelp("r[P2]=parameter(P1,P4)"),
+    /*  77 */ "Move"             OpHelp("r[P2@P3]=r[P1@P3]"),
+    /*  78 */ "Copy"             OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
+    /*  79 */ "SCopy"            OpHelp("r[P2]=r[P1]"),
+    /*  80 */ "IntCopy"          OpHelp("r[P2]=r[P1]"),
+    /*  81 */ "ResultRow"        OpHelp("output=r[P1@P2]"),
+    /*  82 */ "CollSeq"          OpHelp(""),
+    /*  83 */ "AddImm"           OpHelp("r[P1]=r[P1]+P2"),
+    /*  84 */ "RealAffinity"     OpHelp(""),
+    /*  85 */ "Cast"             OpHelp("affinity(r[P1])"),
+    /*  86 */ "Permutation"      OpHelp(""),
+    /*  87 */ "Compare"          OpHelp("r[P1@P3] <-> r[P2@P3]"),
+    /*  88 */ "IsTrue"           OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"),
+    /*  89 */ "Offset"           OpHelp("r[P3] = sqlite_offset(P1)"),
+    /*  90 */ "Column"           OpHelp("r[P3]=PX"),
+    /*  91 */ "Affinity"         OpHelp("affinity(r[P1@P2])"),
+    /*  92 */ "BitAnd"           OpHelp("r[P3]=r[P1]&r[P2]"),
+    /*  93 */ "BitOr"            OpHelp("r[P3]=r[P1]|r[P2]"),
+    /*  94 */ "ShiftLeft"        OpHelp("r[P3]=r[P2]<<r[P1]"),
+    /*  95 */ "ShiftRight"       OpHelp("r[P3]=r[P2]>>r[P1]"),
+    /*  96 */ "Add"              OpHelp("r[P3]=r[P1]+r[P2]"),
+    /*  97 */ "Subtract"         OpHelp("r[P3]=r[P2]-r[P1]"),
+    /*  98 */ "Multiply"         OpHelp("r[P3]=r[P1]*r[P2]"),
+    /*  99 */ "Divide"           OpHelp("r[P3]=r[P2]/r[P1]"),
+    /* 100 */ "Remainder"        OpHelp("r[P3]=r[P2]%r[P1]"),
+    /* 101 */ "Concat"           OpHelp("r[P3]=r[P2]+r[P1]"),
+    /* 102 */ "MakeRecord"       OpHelp("r[P3]=mkrec(r[P1@P2])"),
+    /* 103 */ "BitNot"           OpHelp("r[P2]= ~r[P1]"),
+    /* 104 */ "Count"            OpHelp("r[P2]=count()"),
+    /* 105 */ "ReadCookie"       OpHelp(""),
+    /* 106 */ "String8"          OpHelp("r[P2]='P4'"),
+    /* 107 */ "SetCookie"        OpHelp(""),
+    /* 108 */ "ReopenIdx"        OpHelp("root=P2 iDb=P3"),
+    /* 109 */ "OpenRead"         OpHelp("root=P2 iDb=P3"),
+    /* 110 */ "OpenWrite"        OpHelp("root=P2 iDb=P3"),
+    /* 111 */ "OpenDup"          OpHelp(""),
+    /* 112 */ "OpenAutoindex"    OpHelp("nColumn=P2"),
+    /* 113 */ "OpenEphemeral"    OpHelp("nColumn=P2"),
+    /* 114 */ "SorterOpen"       OpHelp(""),
+    /* 115 */ "SequenceTest"     OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
+    /* 116 */ "OpenPseudo"       OpHelp("P3 columns in r[P2]"),
+    /* 117 */ "Close"            OpHelp(""),
+    /* 118 */ "ColumnsUsed"      OpHelp(""),
+    /* 119 */ "SeekHit"          OpHelp("seekHit=P2"),
+    /* 120 */ "Sequence"         OpHelp("r[P2]=cursor[P1].ctr++"),
+    /* 121 */ "NewRowid"         OpHelp("r[P2]=rowid"),
+    /* 122 */ "Insert"           OpHelp("intkey=r[P3] data=r[P2]"),
+    /* 123 */ "InsertInt"        OpHelp("intkey=P3 data=r[P2]"),
+    /* 124 */ "Delete"           OpHelp(""),
+    /* 125 */ "ResetCount"       OpHelp(""),
+    /* 126 */ "SorterCompare"    OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
+    /* 127 */ "SorterData"       OpHelp("r[P2]=data"),
+    /* 128 */ "RowData"          OpHelp("r[P2]=data"),
+    /* 129 */ "Rowid"            OpHelp("r[P2]=rowid"),
+    /* 130 */ "NullRow"          OpHelp(""),
+    /* 131 */ "SeekEnd"          OpHelp(""),
+    /* 132 */ "SorterInsert"     OpHelp("key=r[P2]"),
+    /* 133 */ "IdxInsert"        OpHelp("key=r[P2]"),
+    /* 134 */ "IdxDelete"        OpHelp("key=r[P2@P3]"),
+    /* 135 */ "DeferredSeek"     OpHelp("Move P3 to P1.rowid if needed"),
+    /* 136 */ "IdxRowid"         OpHelp("r[P2]=rowid"),
+    /* 137 */ "Destroy"          OpHelp(""),
+    /* 138 */ "Clear"            OpHelp(""),
+    /* 139 */ "ResetSorter"      OpHelp(""),
+    /* 140 */ "CreateBtree"      OpHelp("r[P2]=root iDb=P1 flags=P3"),
+    /* 141 */ "Real"             OpHelp("r[P2]=P4"),
+    /* 142 */ "SqlExec"          OpHelp(""),
+    /* 143 */ "ParseSchema"      OpHelp(""),
+    /* 144 */ "LoadAnalysis"     OpHelp(""),
+    /* 145 */ "DropTable"        OpHelp(""),
+    /* 146 */ "DropIndex"        OpHelp(""),
+    /* 147 */ "DropTrigger"      OpHelp(""),
+    /* 148 */ "IntegrityCk"      OpHelp(""),
+    /* 149 */ "RowSetAdd"        OpHelp("rowset(P1)=r[P2]"),
+    /* 150 */ "Param"            OpHelp(""),
+    /* 151 */ "FkCounter"        OpHelp("fkctr[P1]+=P2"),
+    /* 152 */ "MemMax"           OpHelp("r[P1]=max(r[P1],r[P2])"),
+    /* 153 */ "OffsetLimit"      OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"),
+    /* 154 */ "AggInverse"       OpHelp("accum=r[P3] inverse(r[P2@P5])"),
+    /* 155 */ "AggStep"          OpHelp("accum=r[P3] step(r[P2@P5])"),
+    /* 156 */ "AggStep1"         OpHelp("accum=r[P3] step(r[P2@P5])"),
+    /* 157 */ "AggValue"         OpHelp("r[P3]=value N=P2"),
+    /* 158 */ "AggFinal"         OpHelp("accum=r[P1] N=P2"),
+    /* 159 */ "Expire"           OpHelp(""),
+    /* 160 */ "TableLock"        OpHelp("iDb=P1 root=P2 write=P3"),
+    /* 161 */ "VBegin"           OpHelp(""),
+    /* 162 */ "VCreate"          OpHelp(""),
+    /* 163 */ "VDestroy"         OpHelp(""),
+    /* 164 */ "VOpen"            OpHelp(""),
+    /* 165 */ "VColumn"          OpHelp("r[P3]=vcolumn(P2)"),
+    /* 166 */ "VRename"          OpHelp(""),
+    /* 167 */ "Pagecount"        OpHelp(""),
+    /* 168 */ "MaxPgcnt"         OpHelp(""),
+    /* 169 */ "Trace"            OpHelp(""),
+    /* 170 */ "CursorHint"       OpHelp(""),
+    /* 171 */ "Noop"             OpHelp(""),
+    /* 172 */ "Explain"          OpHelp(""),
+    /* 173 */ "Abortable"        OpHelp(""),
   };
   return azName[i];
 }
@@ -32362,12 +32800,25 @@ static int robust_open(const char *z, int f, mode_t m){
 **   unixEnterMutex()
 **     assert( unixMutexHeld() );
 **   unixEnterLeave()
+**
+** To prevent deadlock, the global unixBigLock must must be acquired
+** before the unixInodeInfo.pLockMutex mutex, if both are held.  It is
+** OK to get the pLockMutex without holding unixBigLock first, but if
+** that happens, the unixBigLock mutex must not be acquired until after
+** pLockMutex is released.
+**
+**      OK:     enter(unixBigLock),  enter(pLockInfo)
+**      OK:     enter(unixBigLock)
+**      OK:     enter(pLockInfo)
+**   ERROR:     enter(pLockInfo), enter(unixBigLock)
 */
 static sqlite3_mutex *unixBigLock = 0;
 static void unixEnterMutex(void){
+  assert( sqlite3_mutex_notheld(unixBigLock) );  /* Not a recursive mutex */
   sqlite3_mutex_enter(unixBigLock);
 }
 static void unixLeaveMutex(void){
+  assert( sqlite3_mutex_held(unixBigLock) );
   sqlite3_mutex_leave(unixBigLock);
 }
 #ifdef SQLITE_DEBUG
@@ -32768,16 +33219,34 @@ struct unixFileId {
 ** 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.
+**
+** Mutex rules:
+**
+**  (1) Only the pLockMutex mutex must be held in order to read or write
+**      any of the locking fields:
+**          nShared, nLock, eFileLock, bProcessLock, pUnused
+**
+**  (2) When nRef>0, then the following fields are unchanging and can
+**      be read (but not written) without holding any mutex:
+**          fileId, pLockMutex
+**
+**  (3) With the exceptions above, all the fields may only be read
+**      or written while holding the global unixBigLock mutex.
+**
+** Deadlock prevention:  The global unixBigLock mutex may not
+** be acquired while holding the pLockMutex mutex.  If both unixBigLock
+** and pLockMutex are needed, then unixBigLock must be acquired first.
 */
 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 */
+  sqlite3_mutex *pLockMutex;      /* Hold this mutex for... */
+  int nShared;                      /* Number of SHARED locks held */
+  int nLock;                        /* Number of outstanding file locks */
+  unsigned char eFileLock;          /* One of SHARED_LOCK, RESERVED_LOCK etc. */
+  unsigned char bProcessLock;       /* An exclusive process lock is held */
+  UnixUnusedFd *pUnused;            /* Unused file descriptors to close */
   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
@@ -32793,7 +33262,21 @@ struct unixInodeInfo {
 ** A lists of all unixInodeInfo objects.
 */
 static unixInodeInfo *inodeList = 0;  /* All unixInodeInfo objects */
-static unsigned int nUnusedFd = 0;    /* Total unused file descriptors */
+
+#ifdef SQLITE_DEBUG
+/*
+** True if the inode mutex is held, or not.  Used only within assert()
+** to help verify correct mutex usage.
+*/
+int unixFileMutexHeld(unixFile *pFile){
+  assert( pFile->pInode );
+  return sqlite3_mutex_held(pFile->pInode->pLockMutex);
+}
+int unixFileMutexNotheld(unixFile *pFile){
+  assert( pFile->pInode );
+  return sqlite3_mutex_notheld(pFile->pInode->pLockMutex);
+}
+#endif
 
 /*
 **
@@ -32899,11 +33382,11 @@ static void closePendingFds(unixFile *pFile){
   unixInodeInfo *pInode = pFile->pInode;
   UnixUnusedFd *p;
   UnixUnusedFd *pNext;
+  assert( unixFileMutexHeld(pFile) );
   for(p=pInode->pUnused; p; p=pNext){
     pNext = p->pNext;
     robust_close(pFile, p->fd, __LINE__);
     sqlite3_free(p);
-    nUnusedFd--;
   }
   pInode->pUnused = 0;
 }
@@ -32917,11 +33400,14 @@ static void closePendingFds(unixFile *pFile){
 static void releaseInodeInfo(unixFile *pFile){
   unixInodeInfo *pInode = pFile->pInode;
   assert( unixMutexHeld() );
+  assert( unixFileMutexNotheld(pFile) );
   if( ALWAYS(pInode) ){
     pInode->nRef--;
     if( pInode->nRef==0 ){
       assert( pInode->pShmNode==0 );
+      sqlite3_mutex_enter(pInode->pLockMutex);
       closePendingFds(pFile);
+      sqlite3_mutex_leave(pInode->pLockMutex);
       if( pInode->pPrev ){
         assert( pInode->pPrev->pNext==pInode );
         pInode->pPrev->pNext = pInode->pNext;
@@ -32933,10 +33419,10 @@ static void releaseInodeInfo(unixFile *pFile){
         assert( pInode->pNext->pPrev==pInode );
         pInode->pNext->pPrev = pInode->pPrev;
       }
+      sqlite3_mutex_free(pInode->pLockMutex);
       sqlite3_free(pInode);
     }
   }
-  assert( inodeList!=0 || nUnusedFd==0 );
 }
 
 /*
@@ -33006,7 +33492,6 @@ static int findInodeInfo(
 #else
   fileId.ino = (u64)statbuf.st_ino;
 #endif
-  assert( inodeList!=0 || nUnusedFd==0 );
   pInode = inodeList;
   while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){
     pInode = pInode->pNext;
@@ -33018,6 +33503,13 @@ static int findInodeInfo(
     }
     memset(pInode, 0, sizeof(*pInode));
     memcpy(&pInode->fileId, &fileId, sizeof(fileId));
+    if( sqlite3GlobalConfig.bCoreMutex ){
+      pInode->pLockMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+      if( pInode->pLockMutex==0 ){
+        sqlite3_free(pInode);
+        return SQLITE_NOMEM_BKPT;
+      }
+    }
     pInode->nRef = 1;
     pInode->pNext = inodeList;
     pInode->pPrev = 0;
@@ -33096,7 +33588,7 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
 
   assert( pFile );
   assert( pFile->eFileLock<=SHARED_LOCK );
-  unixEnterMutex(); /* Because pFile->pInode is shared across threads */
+  sqlite3_mutex_enter(pFile->pInode->pLockMutex);
 
   /* Check if a thread in this process holds such a lock */
   if( pFile->pInode->eFileLock>SHARED_LOCK ){
@@ -33121,7 +33613,7 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
   }
 #endif
   
-  unixLeaveMutex();
+  sqlite3_mutex_leave(pFile->pInode->pLockMutex);
   OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved));
 
   *pResOut = reserved;
@@ -33187,8 +33679,8 @@ static int osSetPosixAdvisoryLock(
 static int unixFileLock(unixFile *pFile, struct flock *pLock){
   int rc;
   unixInodeInfo *pInode = pFile->pInode;
-  assert( unixMutexHeld() );
   assert( pInode!=0 );
+  assert( sqlite3_mutex_held(pInode->pLockMutex) );
   if( (pFile->ctrlFlags & (UNIXFILE_EXCL|UNIXFILE_RDONLY))==UNIXFILE_EXCL ){
     if( pInode->bProcessLock==0 ){
       struct flock lock;
@@ -33307,8 +33799,8 @@ static int unixLock(sqlite3_file *id, int eFileLock){
 
   /* This mutex is needed because pFile->pInode is shared across threads
   */
-  unixEnterMutex();
   pInode = pFile->pInode;
+  sqlite3_mutex_enter(pInode->pLockMutex);
 
   /* If some thread using this PID has a lock via a different unixFile*
   ** handle that precludes the requested lock, return BUSY.
@@ -33451,7 +33943,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
   }
 
 end_lock:
-  unixLeaveMutex();
+  sqlite3_mutex_leave(pInode->pLockMutex);
   OSTRACE(("LOCK    %d %s %s (unix)\n", pFile->h, azFileLock(eFileLock), 
       rc==SQLITE_OK ? "ok" : "failed"));
   return rc;
@@ -33464,11 +33956,11 @@ end_lock:
 static void setPendingFd(unixFile *pFile){
   unixInodeInfo *pInode = pFile->pInode;
   UnixUnusedFd *p = pFile->pPreallocatedUnused;
+  assert( unixFileMutexHeld(pFile) );
   p->pNext = pInode->pUnused;
   pInode->pUnused = p;
   pFile->h = -1;
   pFile->pPreallocatedUnused = 0;
-  nUnusedFd++;
 }
 
 /*
@@ -33499,8 +33991,8 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
   if( pFile->eFileLock<=eFileLock ){
     return SQLITE_OK;
   }
-  unixEnterMutex();
   pInode = pFile->pInode;
+  sqlite3_mutex_enter(pInode->pLockMutex);
   assert( pInode->nShared!=0 );
   if( pFile->eFileLock>SHARED_LOCK ){
     assert( pInode->eFileLock==pFile->eFileLock );
@@ -33626,14 +34118,14 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
     */
     pInode->nLock--;
     assert( pInode->nLock>=0 );
-    if( pInode->nLock==0 ){
-      closePendingFds(pFile);
-    }
+    if( pInode->nLock==0 ) closePendingFds(pFile);
   }
 
 end_unlock:
-  unixLeaveMutex();
-  if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock;
+  sqlite3_mutex_leave(pInode->pLockMutex);
+  if( rc==SQLITE_OK ){
+    pFile->eFileLock = eFileLock;
+  }
   return rc;
 }
 
@@ -33704,15 +34196,20 @@ static int closeUnixFile(sqlite3_file *id){
 static int unixClose(sqlite3_file *id){
   int rc = SQLITE_OK;
   unixFile *pFile = (unixFile *)id;
+  unixInodeInfo *pInode = pFile->pInode;
+
+  assert( pInode!=0 );
   verifyDbFile(pFile);
   unixUnlock(id, NO_LOCK);
+  assert( unixFileMutexNotheld(pFile) );
   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 ){
+  sqlite3_mutex_enter(pInode->pLockMutex);
+  if( pInode->nLock ){
     /* If there are outstanding locks, do not actually close the file just
     ** yet because that would clear those locks.  Instead, add the file
     ** descriptor to pInode->pUnused list.  It will be automatically closed 
@@ -33720,6 +34217,7 @@ static int unixClose(sqlite3_file *id){
     */
     setPendingFd(pFile);
   }
+  sqlite3_mutex_leave(pInode->pLockMutex);
   releaseInodeInfo(pFile);
   rc = closeUnixFile(id);
   unixLeaveMutex();
@@ -34317,6 +34815,7 @@ static int semXClose(sqlite3_file *id) {
     unixFile *pFile = (unixFile*)id;
     semXUnlock(id, NO_LOCK);
     assert( pFile );
+    assert( unixFileMutexNotheld(pFile) );
     unixEnterMutex();
     releaseInodeInfo(pFile);
     unixLeaveMutex();
@@ -34431,8 +34930,7 @@ static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){
     *pResOut = 1;
     return SQLITE_OK;
   }
-  unixEnterMutex(); /* Because pFile->pInode is shared across threads */
-  
+  sqlite3_mutex_enter(pFile->pInode->pLockMutex);
   /* Check if a thread in this process holds such a lock */
   if( pFile->pInode->eFileLock>SHARED_LOCK ){
     reserved = 1;
@@ -34456,7 +34954,7 @@ static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){
     }
   }
   
-  unixLeaveMutex();
+  sqlite3_mutex_leave(pFile->pInode->pLockMutex);
   OSTRACE(("TEST WR-LOCK %d %d %d (afp)\n", pFile->h, rc, reserved));
   
   *pResOut = reserved;
@@ -34519,8 +35017,8 @@ static int afpLock(sqlite3_file *id, int eFileLock){
   
   /* This mutex is needed because pFile->pInode is shared across threads
   */
-  unixEnterMutex();
   pInode = pFile->pInode;
+  sqlite3_mutex_enter(pInode->pLockMutex);
 
   /* If some thread using this PID has a lock via a different unixFile*
   ** handle that precludes the requested lock, return BUSY.
@@ -34656,7 +35154,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){
   }
   
 afp_end_lock:
-  unixLeaveMutex();
+  sqlite3_mutex_leave(pInode->pLockMutex);
   OSTRACE(("LOCK    %d %s %s (afp)\n", pFile->h, azFileLock(eFileLock), 
          rc==SQLITE_OK ? "ok" : "failed"));
   return rc;
@@ -34688,8 +35186,8 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
   if( pFile->eFileLock<=eFileLock ){
     return SQLITE_OK;
   }
-  unixEnterMutex();
   pInode = pFile->pInode;
+  sqlite3_mutex_enter(pInode->pLockMutex);
   assert( pInode->nShared!=0 );
   if( pFile->eFileLock>SHARED_LOCK ){
     assert( pInode->eFileLock==pFile->eFileLock );
@@ -34758,14 +35256,14 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
     if( rc==SQLITE_OK ){
       pInode->nLock--;
       assert( pInode->nLock>=0 );
-      if( pInode->nLock==0 ){
-        closePendingFds(pFile);
-      }
+      if( pInode->nLock==0 ) closePendingFds(pFile);
     }
   }
   
-  unixLeaveMutex();
-  if( rc==SQLITE_OK ) pFile->eFileLock = eFileLock;
+  sqlite3_mutex_leave(pInode->pLockMutex);
+  if( rc==SQLITE_OK ){
+    pFile->eFileLock = eFileLock;
+  }
   return rc;
 }
 
@@ -34777,14 +35275,20 @@ static int afpClose(sqlite3_file *id) {
   unixFile *pFile = (unixFile*)id;
   assert( id!=0 );
   afpUnlock(id, NO_LOCK);
+  assert( unixFileMutexNotheld(pFile) );
   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);
+  if( pFile->pInode ){
+    unixInodeInfo *pInode = pFile->pInode;
+    sqlite3_mutex_enter(pInode->pLockMutex);
+    if( pInode->nLock ){
+      /* If there are outstanding locks, do not actually close the file just
+      ** yet because that would clear those locks.  Instead, add the file
+      ** descriptor to pInode->aPending.  It will be automatically closed when
+      ** the last lock is cleared.
+      */
+      setPendingFd(pFile);
+    }
+    sqlite3_mutex_leave(pInode->pLockMutex);
   }
   releaseInodeInfo(pFile);
   sqlite3_free(pFile->lockingContext);
@@ -36090,6 +36594,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
   /* Check to see if a unixShmNode object already exists. Reuse an existing
   ** one if present. Create a new one if necessary.
   */
+  assert( unixFileMutexNotheld(pDbFd) );
   unixEnterMutex();
   pInode = pDbFd->pInode;
   pShmNode = pInode->pShmNode;
@@ -36472,6 +36977,9 @@ static void unixShmBarrier(
 ){
   UNUSED_PARAMETER(fd);
   sqlite3MemoryBarrier();         /* compiler-defined memory barrier */
+  assert( fd->pMethods->xLock==nolockLock 
+       || unixFileMutexNotheld((unixFile*)fd) 
+  );
   unixEnterMutex();               /* Also mutex, for redundancy */
   unixLeaveMutex();
 }
@@ -36513,6 +37021,7 @@ static int unixShmUnmap(
 
   /* If pShmNode->nRef has reached 0, then close the underlying
   ** shared-memory file, too */
+  assert( unixFileMutexNotheld(pDbFd) );
   unixEnterMutex();
   assert( pShmNode->nRef>0 );
   pShmNode->nRef--;
@@ -36839,7 +37348,7 @@ IOMETHODS(
 IOMETHODS(
   nolockIoFinder,           /* Finder function name */
   nolockIoMethods,          /* sqlite3_io_methods object name */
-  3,                        /* shared memory is disabled */
+  3,                        /* shared memory and mmap are enabled */
   nolockClose,              /* xClose method */
   nolockLock,               /* xLock method */
   nolockUnlock,             /* xUnlock method */
@@ -37335,7 +37844,7 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
   **
   ** Even if a subsequent open() call does succeed, the consequences of
   ** not searching for a reusable file descriptor are not dire.  */
-  if( nUnusedFd>0 && 0==osStat(zPath, &sStat) ){
+  if( inodeList!=0 && 0==osStat(zPath, &sStat) ){
     unixInodeInfo *pInode;
 
     pInode = inodeList;
@@ -37345,12 +37854,14 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
     }
     if( pInode ){
       UnixUnusedFd **pp;
+      assert( sqlite3_mutex_notheld(pInode->pLockMutex) );
+      sqlite3_mutex_enter(pInode->pLockMutex);
       for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext));
       pUnused = *pp;
       if( pUnused ){
-        nUnusedFd--;
         *pp = pUnused->pNext;
       }
+      sqlite3_mutex_leave(pInode->pLockMutex);
     }
   }
   unixLeaveMutex();
@@ -42553,6 +43064,9 @@ 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;
+#if SQLITE_MAX_MMAP_SIZE>0
+  sqlite3_int64 oldMmapSize;
+#endif
 
   assert( pFile );
   SimulateIOError(return SQLITE_IOERR_TRUNCATE);
@@ -42568,6 +43082,15 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
     nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
   }
 
+#if SQLITE_MAX_MMAP_SIZE>0
+  if( pFile->pMapRegion ){
+    oldMmapSize = pFile->mmapSize;
+  }else{
+    oldMmapSize = 0;
+  }
+  winUnmapfile(pFile);
+#endif
+
   /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
   if( winSeekFile(pFile, nByte) ){
     rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno,
@@ -42580,12 +43103,12 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
   }
 
 #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 && nByte<pFile->mmapSize ){
-    pFile->mmapSize = nByte;
+  if( rc==SQLITE_OK && oldMmapSize>0 ){
+    if( oldMmapSize>nByte ){
+      winMapfile(pFile, -1);
+    }else{
+      winMapfile(pFile, oldMmapSize);
+    }
   }
 #endif
 
@@ -45773,8 +46296,8 @@ SQLITE_API int sqlite3_os_end(void){
 ** This file also implements interface sqlite3_serialize() and
 ** sqlite3_deserialize().
 */
-#ifdef SQLITE_ENABLE_DESERIALIZE
 /* #include "sqliteInt.h" */
+#ifdef SQLITE_ENABLE_DESERIALIZE
 
 /*
 ** Forward declaration of objects used by this utility
@@ -49022,30 +49545,23 @@ struct RowSet {
 #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.
+** Allocate a RowSet object.  Return NULL if a memory allocation
+** error occurs.
 */
-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;
+SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3 *db){
+  RowSet *p = sqlite3DbMallocRawNN(db, sizeof(*p));
+  if( p ){
+    int N = sqlite3DbMallocSize(db, p);
+    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;
 }
 
@@ -49054,7 +49570,8 @@ SQLITE_PRIVATE RowSet *sqlite3RowSetInit(sqlite3 *db, void *pSpace, unsigned int
 ** the RowSet has allocated over its lifetime.  This routine is
 ** the destructor for the RowSet.
 */
-SQLITE_PRIVATE void sqlite3RowSetClear(RowSet *p){
+SQLITE_PRIVATE void sqlite3RowSetClear(void *pArg){
+  RowSet *p = (RowSet*)pArg;
   struct RowSetChunk *pChunk, *pNextChunk;
   for(pChunk=p->pChunk; pChunk; pChunk = pNextChunk){
     pNextChunk = pChunk->pNextChunk;
@@ -49068,6 +49585,16 @@ SQLITE_PRIVATE void sqlite3RowSetClear(RowSet *p){
   p->rsFlags = ROWSET_SORTED;
 }
 
+/*
+** 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 sqlite3RowSetDelete(void *pArg){
+  sqlite3RowSetClear(pArg);
+  sqlite3DbFree(((RowSet*)pArg)->db, pArg);
+}
+
 /*
 ** Allocate a new RowSetEntry object that is associated with the
 ** given RowSet.  Return a pointer to the new and completely uninitialized
@@ -49555,6 +50082,8 @@ SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal);
 SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot);
 SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot);
 SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal);
+SQLITE_PRIVATE int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot);
+SQLITE_PRIVATE void sqlite3WalSnapshotUnlock(Wal *pWal);
 #endif
 
 #ifdef SQLITE_ENABLE_ZIPVFS
@@ -50548,8 +51077,12 @@ static int assert_pager_state(Pager *p){
 ** to "print *pPager" in gdb:
 **
 ** (gdb) printf "%s", print_pager_state(pPager)
+**
+** This routine has external linkage in order to suppress compiler warnings
+** about an unused function.  It is enclosed within SQLITE_DEBUG and so does
+** not appear in normal builds.
 */
-static char *print_pager_state(Pager *p){
+char *print_pager_state(Pager *p){
   static char zRet[1024];
 
   sqlite3_snprintf(1024, zRet,
@@ -51315,7 +51848,6 @@ static void pager_reset(Pager *pPager){
 ** Return the pPager->iDataVersion value
 */
 SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager *pPager){
-  assert( pPager->eState>PAGER_OPEN );
   return pPager->iDataVersion;
 }
 
@@ -55933,9 +56465,10 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
     ** backup in progress needs to be restarted.  */
     sqlite3BackupRestart(pPager->pBackup);
   }else{
+    PgHdr *pList;
     if( pagerUseWal(pPager) ){
-      PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
       PgHdr *pPageOne = 0;
+      pList = sqlite3PcacheDirtyList(pPager->pPCache);
       if( pList==0 ){
         /* Must have at least one page for the WAL commit flag.
         ** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */
@@ -55956,14 +56489,14 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
       ** should be used.  No rollback journal is created if batch-atomic-write
       ** is enabled.
       */
-      sqlite3_file *fd = pPager->fd;
 #ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
-      const int bBatch = zMaster==0    /* An SQLITE_IOCAP_BATCH_ATOMIC commit */
+      sqlite3_file *fd = pPager->fd;
+      int bBatch = zMaster==0    /* An SQLITE_IOCAP_BATCH_ATOMIC commit */
         && (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC)
         && !pPager->noSync
         && sqlite3JournalIsInMemory(pPager->jfd);
 #else
-# define bBatch 0
+#     define bBatch 0
 #endif
 
 #ifdef SQLITE_ENABLE_ATOMIC_WRITE
@@ -56015,15 +56548,16 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
           }
         }
       }
-#else 
+#else  /* SQLITE_ENABLE_ATOMIC_WRITE */
 #ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
       if( zMaster ){
         rc = sqlite3JournalCreate(pPager->jfd);
         if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
+        assert( bBatch==0 );
       }
 #endif
       rc = pager_incr_changecounter(pPager, 0);
-#endif
+#endif /* !SQLITE_ENABLE_ATOMIC_WRITE */
       if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
   
       /* Write the master journal name into the journal file. If a master 
@@ -56047,24 +56581,36 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
       rc = syncJournal(pPager, 0);
       if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
 
+      pList = sqlite3PcacheDirtyList(pPager->pPCache);
+#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
       if( bBatch ){
-        /* The pager is now in DBMOD state. But regardless of what happens
-        ** next, attempting to play the journal back into the database would
-        ** be unsafe. Close it now to make sure that does not happen.  */
-        sqlite3OsClose(pPager->jfd);
         rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0);
-        if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
-      }
-      rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache));
-      if( bBatch ){
         if( rc==SQLITE_OK ){
-          rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);
+          rc = pager_write_pagelist(pPager, pList);
+          if( rc==SQLITE_OK ){
+            rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);
+          }
+          if( rc!=SQLITE_OK ){
+            sqlite3OsFileControlHint(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0);
+          }
         }
-        if( rc!=SQLITE_OK ){
-          sqlite3OsFileControlHint(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0);
+
+        if( (rc&0xFF)==SQLITE_IOERR && rc!=SQLITE_IOERR_NOMEM ){
+          rc = sqlite3JournalCreate(pPager->jfd);
+          if( rc!=SQLITE_OK ){
+            sqlite3OsClose(pPager->jfd);
+            goto commit_phase_one_exit;
+          }
+          bBatch = 0;
+        }else{
+          sqlite3OsClose(pPager->jfd);
         }
       }
+#endif /* SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
 
+      if( bBatch==0 ){
+        rc = pager_write_pagelist(pPager, pList);
+      }
       if( rc!=SQLITE_OK ){
         assert( rc!=SQLITE_IOERR_BLOCKED );
         goto commit_phase_one_exit;
@@ -56816,13 +57362,6 @@ SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *pPager, int eMode){
 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
@@ -57191,6 +57730,38 @@ SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager){
   }
   return rc;
 }
+
+/*
+** The caller currently has a read transaction open on the database.
+** If this is not a WAL database, SQLITE_ERROR is returned. Otherwise,
+** this function takes a SHARED lock on the CHECKPOINTER slot and then
+** checks if the snapshot passed as the second argument is still 
+** available. If so, SQLITE_OK is returned.
+**
+** If the snapshot is not available, SQLITE_ERROR is returned. Or, if
+** the CHECKPOINTER lock cannot be obtained, SQLITE_BUSY. If any error
+** occurs (any value other than SQLITE_OK is returned), the CHECKPOINTER
+** lock is released before returning.
+*/
+SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot){
+  int rc;
+  if( pPager->pWal ){
+    rc = sqlite3WalSnapshotCheck(pPager->pWal, pSnapshot);
+  }else{
+    rc = SQLITE_ERROR;
+  }
+  return rc;
+}
+
+/*
+** Release a lock obtained by an earlier successful call to
+** sqlite3PagerSnapshotCheck().
+*/
+SQLITE_PRIVATE void sqlite3PagerSnapshotUnlock(Pager *pPager){
+  assert( pPager->pWal );
+  return sqlite3WalSnapshotUnlock(pPager->pWal);
+}
+
 #endif /* SQLITE_ENABLE_SNAPSHOT */
 #endif /* !SQLITE_OMIT_WAL */
 
@@ -57472,6 +58043,18 @@ SQLITE_PRIVATE int sqlite3WalTrace = 0;
 # define WALTRACE(X)
 #endif
 
+/*
+** WAL mode depends on atomic aligned 32-bit loads and stores in a few
+** places.  The following macros try to make this explicit.
+*/
+#if GCC_VESRION>=5004000
+# define AtomicLoad(PTR)       __atomic_load_n((PTR),__ATOMIC_RELAXED)
+# define AtomicStore(PTR,VAL)  __atomic_store_n((PTR),(VAL),__ATOMIC_RELAXED)
+#else
+# define AtomicLoad(PTR)       (*(PTR))
+# define AtomicStore(PTR,VAL)  (*(PTR) = (VAL))
+#endif
+
 /*
 ** The maximum (and only) versions of the wal and wal-index formats
 ** that may be interpreted by this version of SQLite.
@@ -58094,48 +58677,51 @@ static int walNextHash(int iPriorHash){
   return (iPriorHash+1)&(HASHTABLE_NSLOT-1);
 }
 
+/*
+** An instance of the WalHashLoc object is used to describe the location
+** of a page hash table in the wal-index.  This becomes the return value
+** from walHashGet().
+*/
+typedef struct WalHashLoc WalHashLoc;
+struct WalHashLoc {
+  volatile ht_slot *aHash;  /* Start of the wal-index hash table */
+  volatile u32 *aPgno;      /* aPgno[1] is the page of first frame indexed */
+  u32 iZero;                /* One less than the frame number of first indexed*/
+};
+
 /* 
 ** Return pointers to the hash table and page number array stored on
 ** page iHash of the wal-index. The wal-index is broken into 32KB pages
 ** numbered starting from 0.
 **
-** Set output variable *paHash to point to the start of the hash table
-** in the wal-index file. Set *piZero to one less than the frame 
+** Set output variable pLoc->aHash to point to the start of the hash table
+** in the wal-index file. Set pLoc->iZero to one less than the frame 
 ** 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.
+** (pLoc->iZero+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).
+** Finally, set pLoc->aPgno so that pLoc->aPgno[1] is the page number of the
+** first frame indexed by the hash table, frame (pLoc->iZero+1).
 */
 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] */
+  WalHashLoc *pLoc                /* OUT: Hash table location */
 ){
   int rc;                         /* Return code */
-  volatile u32 *aPgno;
 
-  rc = walIndexPage(pWal, iHash, &aPgno);
+  rc = walIndexPage(pWal, iHash, &pLoc->aPgno);
   assert( rc==SQLITE_OK || iHash>0 );
 
   if( rc==SQLITE_OK ){
-    u32 iZero;
-    volatile ht_slot *aHash;
-
-    aHash = (volatile ht_slot *)&aPgno[HASHTABLE_NPAGE];
+    pLoc->aHash = (volatile ht_slot *)&pLoc->aPgno[HASHTABLE_NPAGE];
     if( iHash==0 ){
-      aPgno = &aPgno[WALINDEX_HDR_SIZE/sizeof(u32)];
-      iZero = 0;
+      pLoc->aPgno = &pLoc->aPgno[WALINDEX_HDR_SIZE/sizeof(u32)];
+      pLoc->iZero = 0;
     }else{
-      iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE;
+      pLoc->iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE;
     }
-  
-    *paPgno = &aPgno[-1];
-    *paHash = aHash;
-    *piZero = iZero;
+    pLoc->aPgno = &pLoc->aPgno[-1];
   }
   return rc;
 }
@@ -58181,9 +58767,7 @@ static u32 walFramePgno(Wal *pWal, u32 iFrame){
 ** 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) */
+  WalHashLoc sLoc;                /* Hash table location */
   int iLimit = 0;                 /* Zero values greater than this */
   int nByte;                      /* Number of bytes to zero in aPgno[] */
   int i;                          /* Used to iterate through aHash[] */
@@ -58201,24 +58785,24 @@ static void walCleanupHash(Wal *pWal){
   */
   assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) );
   assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] );
-  walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &aHash, &aPgno, &iZero);
+  walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &sLoc);
 
   /* Zero all hash-table entries that correspond to frame numbers greater
   ** than pWal->hdr.mxFrame.
   */
-  iLimit = pWal->hdr.mxFrame - iZero;
+  iLimit = pWal->hdr.mxFrame - sLoc.iZero;
   assert( iLimit>0 );
   for(i=0; i<HASHTABLE_NSLOT; i++){
-    if( aHash[i]>iLimit ){
-      aHash[i] = 0;
+    if( sLoc.aHash[i]>iLimit ){
+      sLoc.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);
+  nByte = (int)((char *)sLoc.aHash - (char *)&sLoc.aPgno[iLimit+1]);
+  memset((void *)&sLoc.aPgno[iLimit+1], 0, nByte);
 
 #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
   /* Verify that the every entry in the mapping region is still reachable
@@ -58228,10 +58812,10 @@ static void walCleanupHash(Wal *pWal){
     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;
+      for(iKey=walHash(sLoc.aPgno[j]);sLoc.aHash[iKey];iKey=walNextHash(iKey)){
+        if( sLoc.aHash[iKey]==j ) break;
       }
-      assert( aHash[iKey]==j );
+      assert( sLoc.aHash[iKey]==j );
     }
   }
 #endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
@@ -58244,11 +58828,9 @@ static void walCleanupHash(Wal *pWal){
 */
 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 */
+  WalHashLoc sLoc;                /* Wal-index hash table location */
 
-  rc = walHashGet(pWal, walFramePage(iFrame), &aHash, &aPgno, &iZero);
+  rc = walHashGet(pWal, walFramePage(iFrame), &sLoc);
 
   /* Assuming the wal-index file was successfully mapped, populate the
   ** page number array and hash table entry.
@@ -58258,15 +58840,16 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
     int idx;                      /* Value to write to hash-table slot */
     int nCollide;                 /* Number of hash collisions */
 
-    idx = iFrame - iZero;
+    idx = iFrame - sLoc.iZero;
     assert( idx <= HASHTABLE_NSLOT/2 + 1 );
     
     /* If this is the first entry to be added to this hash-table, zero the
     ** entire hash table and aPgno[] array before proceeding. 
     */
     if( idx==1 ){
-      int nByte = (int)((u8 *)&aHash[HASHTABLE_NSLOT] - (u8 *)&aPgno[1]);
-      memset((void*)&aPgno[1], 0, nByte);
+      int nByte = (int)((u8 *)&sLoc.aHash[HASHTABLE_NSLOT]
+                               - (u8 *)&sLoc.aPgno[1]);
+      memset((void*)&sLoc.aPgno[1], 0, nByte);
     }
 
     /* If the entry in aPgno[] is already set, then the previous writer
@@ -58275,18 +58858,18 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
     ** Remove the remnants of that writers uncommitted transaction from 
     ** the hash-table before writing any new entries.
     */
-    if( aPgno[idx] ){
+    if( sLoc.aPgno[idx] ){
       walCleanupHash(pWal);
-      assert( !aPgno[idx] );
+      assert( !sLoc.aPgno[idx] );
     }
 
     /* Write the aPgno[] array entry and the hash-table slot. */
     nCollide = idx;
-    for(iKey=walHash(iPage); aHash[iKey]; iKey=walNextHash(iKey)){
+    for(iKey=walHash(iPage); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){
       if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT;
     }
-    aPgno[idx] = iPage;
-    aHash[iKey] = (ht_slot)idx;
+    sLoc.aPgno[idx] = iPage;
+    sLoc.aHash[iKey] = (ht_slot)idx;
 
 #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
     /* Verify that the number of entries in the hash table exactly equals
@@ -58295,7 +58878,7 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
     {
       int i;           /* Loop counter */
       int nEntry = 0;  /* Number of entries in the hash table */
-      for(i=0; i<HASHTABLE_NSLOT; i++){ if( aHash[i] ) nEntry++; }
+      for(i=0; i<HASHTABLE_NSLOT; i++){ if( sLoc.aHash[i] ) nEntry++; }
       assert( nEntry==idx );
     }
 
@@ -58307,10 +58890,12 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
     if( (idx&0x3ff)==0 ){
       int i;           /* Loop counter */
       for(i=1; i<=idx; i++){
-        for(iKey=walHash(aPgno[i]); aHash[iKey]; iKey=walNextHash(iKey)){
-          if( aHash[iKey]==i ) break;
+        for(iKey=walHash(sLoc.aPgno[i]);
+            sLoc.aHash[iKey];
+            iKey=walNextHash(iKey)){
+          if( sLoc.aHash[iKey]==i ) break;
         }
-        assert( aHash[iKey]==i );
+        assert( sLoc.aHash[iKey]==i );
       }
     }
 #endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
@@ -58848,33 +59433,31 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
   }
 
   for(i=walFramePage(nBackfill+1); rc==SQLITE_OK && i<nSegment; i++){
-    volatile ht_slot *aHash;
-    u32 iZero;
-    volatile u32 *aPgno;
+    WalHashLoc sLoc;
 
-    rc = walHashGet(pWal, i, &aHash, &aPgno, &iZero);
+    rc = walHashGet(pWal, i, &sLoc);
     if( rc==SQLITE_OK ){
       int j;                      /* Counter variable */
       int nEntry;                 /* Number of entries in this segment */
       ht_slot *aIndex;            /* Sorted index for this segment */
 
-      aPgno++;
+      sLoc.aPgno++;
       if( (i+1)==nSegment ){
-        nEntry = (int)(iLast - iZero);
+        nEntry = (int)(iLast - sLoc.iZero);
       }else{
-        nEntry = (int)((u32*)aHash - (u32*)aPgno);
+        nEntry = (int)((u32*)sLoc.aHash - (u32*)sLoc.aPgno);
       }
-      aIndex = &((ht_slot *)&p->aSegment[p->nSegment])[iZero];
-      iZero++;
+      aIndex = &((ht_slot *)&p->aSegment[p->nSegment])[sLoc.iZero];
+      sLoc.iZero++;
   
       for(j=0; j<nEntry; j++){
         aIndex[j] = (ht_slot)j;
       }
-      walMergesort((u32 *)aPgno, aTmp, aIndex, &nEntry);
-      p->aSegment[i].iZero = iZero;
+      walMergesort((u32 *)sLoc.aPgno, aTmp, aIndex, &nEntry);
+      p->aSegment[i].iZero = sLoc.iZero;
       p->aSegment[i].nEntry = nEntry;
       p->aSegment[i].aIndex = aIndex;
-      p->aSegment[i].aPgno = (u32 *)aPgno;
+      p->aSegment[i].aPgno = (u32 *)sLoc.aPgno;
     }
   }
   sqlite3_free(aTmp);
@@ -59049,7 +59632,6 @@ static int walCheckpoint(
     if( pIter
      && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0),1))==SQLITE_OK
     ){
-      i64 nSize;                    /* Current size of database file */
       u32 nBackfill = pInfo->nBackfill;
 
       pInfo->nBackfillAttempted = mxSafeFrame;
@@ -59062,6 +59644,7 @@ static int walCheckpoint(
       */
       if( rc==SQLITE_OK ){
         i64 nReq = ((i64)mxPage * szPage);
+        i64 nSize;                    /* Current size of database file */
         rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
         if( rc==SQLITE_OK && nSize<nReq ){
           sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
@@ -59769,7 +60352,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
   }
 #endif
   for(i=1; i<WAL_NREADER; i++){
-    u32 thisMark = pInfo->aReadMark[i];
+    u32 thisMark = AtomicLoad(pInfo->aReadMark+i);
     if( mxReadMark<=thisMark && thisMark<=mxFrame ){
       assert( thisMark!=READMARK_NOT_USED );
       mxReadMark = thisMark;
@@ -59782,7 +60365,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
     for(i=1; i<WAL_NREADER; i++){
       rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
       if( rc==SQLITE_OK ){
-        mxReadMark = pInfo->aReadMark[i] = mxFrame;
+        mxReadMark = AtomicStore(pInfo->aReadMark+i,mxFrame);
         mxI = i;
         walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
         break;
@@ -59834,9 +60417,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
   ** we can guarantee that the checkpointer that set nBackfill could not
   ** see any pages past pWal->hdr.mxFrame, this problem does not come up.
   */
-  pWal->minFrame = pInfo->nBackfill+1;
+  pWal->minFrame = AtomicLoad(&pInfo->nBackfill)+1;
   walShmBarrier(pWal);
-  if( pInfo->aReadMark[mxI]!=mxReadMark
+  if( AtomicLoad(pInfo->aReadMark+mxI)!=mxReadMark
    || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
   ){
     walUnlockShared(pWal, WAL_READ_LOCK(mxI));
@@ -59887,16 +60470,14 @@ SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal){
       }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] */
+          WalHashLoc sLoc;          /* Hash table location */
           u32 pgno;                 /* Page number in db file */
           i64 iDbOff;               /* Offset of db file entry */
           i64 iWalOff;              /* Offset of wal file entry */
 
-          rc = walHashGet(pWal, walFramePage(i), &dummy, &aPgno, &iZero);
+          rc = walHashGet(pWal, walFramePage(i), &sLoc);
           if( rc!=SQLITE_OK ) break;
-          pgno = aPgno[i-iZero];
+          pgno = sLoc.aPgno[i-sLoc.iZero];
           iDbOff = (i64)(pgno-1) * szPage;
 
           if( iDbOff+szPage<=szDb ){
@@ -59937,7 +60518,7 @@ SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal){
 **
 ** 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
+** Pager layer will use this to know that its cache is stale and
 ** needs to be flushed.
 */
 SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
@@ -59999,7 +60580,7 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
         /* 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
+        ** true, return SQLITE_ERROR_SNAPSHOT. Otherwise, overwrite pWal->hdr
         ** with *pSnapshot and set *pChanged as appropriate for opening the
         ** snapshot.  */
         if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
@@ -60009,11 +60590,12 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
           memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr));
           *pChanged = bChanged;
         }else{
-          rc = SQLITE_BUSY_SNAPSHOT;
+          rc = SQLITE_ERROR_SNAPSHOT;
         }
 
         /* Release the shared CKPT lock obtained above. */
         walUnlockShared(pWal, WAL_CKPT_LOCK);
+        pWal->minFrame = 1;
       }
 
 
@@ -60097,21 +60679,20 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
   */
   iMinHash = walFramePage(pWal->minFrame);
   for(iHash=walFramePage(iLast); iHash>=iMinHash; 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] */
+    WalHashLoc sLoc;              /* Hash table location */
     int iKey;                     /* Hash slot index */
     int nCollide;                 /* Number of hash collisions remaining */
     int rc;                       /* Error code */
 
-    rc = walHashGet(pWal, iHash, &aHash, &aPgno, &iZero);
+    rc = walHashGet(pWal, iHash, &sLoc);
     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 ){
+    for(iKey=walHash(pgno); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){
+      u32 iFrame = sLoc.aHash[iKey] + sLoc.iZero;
+      if( iFrame<=iLast && iFrame>=pWal->minFrame
+       && sLoc.aPgno[sLoc.aHash[iKey]]==pgno ){
         assert( iFrame>iRead || CORRUPT_DB );
         iRead = iFrame;
       }
@@ -60986,6 +61567,43 @@ SQLITE_API int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){
   if( pHdr1->mxFrame>pHdr2->mxFrame ) return +1;
   return 0;
 }
+
+/*
+** The caller currently has a read transaction open on the database.
+** This function takes a SHARED lock on the CHECKPOINTER slot and then
+** checks if the snapshot passed as the second argument is still 
+** available. If so, SQLITE_OK is returned.
+**
+** If the snapshot is not available, SQLITE_ERROR is returned. Or, if
+** the CHECKPOINTER lock cannot be obtained, SQLITE_BUSY. If any error
+** occurs (any value other than SQLITE_OK is returned), the CHECKPOINTER
+** lock is released before returning.
+*/
+SQLITE_PRIVATE int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot){
+  int rc;
+  rc = walLockShared(pWal, WAL_CKPT_LOCK);
+  if( rc==SQLITE_OK ){
+    WalIndexHdr *pNew = (WalIndexHdr*)pSnapshot;
+    if( memcmp(pNew->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
+     || pNew->mxFrame<walCkptInfo(pWal)->nBackfillAttempted
+    ){
+      rc = SQLITE_ERROR_SNAPSHOT;
+      walUnlockShared(pWal, WAL_CKPT_LOCK);
+    }
+  }
+  return rc;
+}
+
+/*
+** Release a lock obtained by an earlier successful call to
+** sqlite3WalSnapshotCheck().
+*/
+SQLITE_PRIVATE void sqlite3WalSnapshotUnlock(Wal *pWal){
+  assert( pWal );
+  walUnlockShared(pWal, WAL_CKPT_LOCK);
+}
+
+
 #endif /* SQLITE_ENABLE_SNAPSHOT */
 
 #ifdef SQLITE_ENABLE_ZIPVFS
@@ -65331,7 +65949,7 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){
 ** when A already has a read lock, we encourage A to give up and let B
 ** proceed.
 */
-SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
+SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
   BtShared *pBt = p->pBt;
   int rc = SQLITE_OK;
 
@@ -65347,6 +65965,12 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
   }
   assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 );
 
+  if( (p->db->flags & SQLITE_ResetDatabase) 
+   && sqlite3PagerIsreadonly(pBt->pPager)==0 
+  ){
+    pBt->btsFlags &= ~BTS_READ_ONLY;
+  }
+
   /* Write transactions are not possible on a read-only database */
   if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){
     rc = SQLITE_READONLY;
@@ -65406,6 +66030,11 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
         rc = sqlite3PagerBegin(pBt->pPager,wrflag>1,sqlite3TempInMemory(p->db));
         if( rc==SQLITE_OK ){
           rc = newDatabase(pBt);
+        }else if( rc==SQLITE_BUSY_SNAPSHOT && pBt->inTransaction==TRANS_NONE ){
+          /* if there was no transaction opened when this function was
+          ** called and SQLITE_BUSY_SNAPSHOT is returned, change the error
+          ** code to SQLITE_BUSY. */
+          rc = SQLITE_BUSY;
         }
       }
     }
@@ -65457,14 +66086,18 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
     }
   }
 
-
 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);
+  if( rc==SQLITE_OK ){
+    if( pSchemaVersion ){
+      *pSchemaVersion = get4byte(&pBt->pPage1->aData[40]);
+    }
+    if( wrflag ){
+      /* This call makes sure that the pager has the correct number of
+      ** open savepoints. If the second parameter is greater than 0 and
+      ** the sub-journal is not already open, then it will be opened here.
+      */
+      rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint);
+    }
   }
 
   btreeIntegrity(p);
@@ -67211,6 +67844,23 @@ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
   return rc;
 }
 
+/*
+** This function is a no-op if cursor pCur does not point to a valid row.
+** Otherwise, if pCur is valid, configure it so that the next call to
+** sqlite3BtreeNext() is a no-op.
+*/
+#ifndef SQLITE_OMIT_WINDOWFUNC
+SQLITE_PRIVATE void sqlite3BtreeSkipNext(BtCursor *pCur){
+  /* We believe that the cursor must always be in the valid state when
+  ** this routine is called, but the proof is difficult, so we add an
+  ** ALWaYS() test just in case we are wrong. */
+  if( ALWAYS(pCur->eState==CURSOR_VALID) ){
+    pCur->eState = CURSOR_SKIPNEXT;
+    pCur->skipNext = 1;
+  }
+}
+#endif /* SQLITE_OMIT_WINDOWFUNC */
+
 /* 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.
@@ -67615,7 +68265,16 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
 
   pPage = pCur->pPage;
   idx = ++pCur->ix;
-  assert( pPage->isInit );
+  if( !pPage->isInit ){
+    /* The only known way for this to happen is for there to be a
+    ** recursive SQL function that does a DELETE operation as part of a
+    ** SELECT which deletes content out from under an active cursor
+    ** in a corrupt database file where the table being DELETE-ed from
+    ** has pages in common with the table being queried.  See TH3
+    ** module cov1/btree78.test testcase 220 (2018-06-08) for an
+    ** example. */
+    return SQLITE_CORRUPT_BKPT;
+  }
 
   /* If the database file is corrupt, it is possible for the value of idx 
   ** to be invalid here. This can only occur if a second cursor modifies
@@ -71327,8 +71986,7 @@ static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){
 ** Also check that the page number is in bounds.
 */
 static int checkRef(IntegrityCk *pCheck, Pgno iPage){
-  if( iPage==0 ) return 1;
-  if( iPage>pCheck->nPage ){
+  if( iPage>pCheck->nPage || iPage==0 ){
     checkAppendMsg(pCheck, "invalid page number %d", iPage);
     return 1;
   }
@@ -71383,17 +72041,12 @@ static void checkList(
 ){
   int i;
   int expected = N;
-  int iFirst = iPage;
-  while( N-- > 0 && pCheck->mxErr ){
+  int nErrAtStart = pCheck->nErr;
+  while( iPage!=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;
+    N--;
     if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){
       checkAppendMsg(pCheck, "failed to get page %d", iPage);
       break;
@@ -71437,10 +72090,12 @@ static void checkList(
 #endif
     iPage = get4byte(pOvflData);
     sqlite3PagerUnref(pOvflPage);
-
-    if( isFreeList && N<(iPage!=0) ){
-      checkAppendMsg(pCheck, "free-page count in header is too small");
-    }
+  }
+  if( N && nErrAtStart==pCheck->nErr ){
+    checkAppendMsg(pCheck,
+      "%s is %d but should be %d",
+      isFreeList ? "size" : "overflow list length",
+      expected-N, expected);
   }
 }
 #endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@@ -71834,6 +72489,24 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
 
   /* Check all the tables.
   */
+#ifndef SQLITE_OMIT_AUTOVACUUM
+  if( pBt->autoVacuum ){
+    int mx = 0;
+    int mxInHdr;
+    for(i=0; (int)i<nRoot; i++) if( mx<aRoot[i] ) mx = aRoot[i];
+    mxInHdr = get4byte(&pBt->pPage1->aData[52]);
+    if( mx!=mxInHdr ){
+      checkAppendMsg(&sCheck,
+        "max rootpage (%d) disagrees with header (%d)",
+        mx, mxInHdr
+      );
+    }
+  }else if( get4byte(&pBt->pPage1->aData[64])!=0 ){
+    checkAppendMsg(&sCheck,
+      "incremental_vacuum enabled with a max rootpage of zero"
+    );
+  }
+#endif
   testcase( pBt->db->flags & SQLITE_CellSizeCk );
   pBt->db->flags &= ~SQLITE_CellSizeCk;
   for(i=0; (int)i<nRoot && sCheck.mxErr; i++){
@@ -72115,11 +72788,11 @@ SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){
   pBt->btsFlags &= ~BTS_NO_WAL;
   if( iVersion==1 ) pBt->btsFlags |= BTS_NO_WAL;
 
-  rc = sqlite3BtreeBeginTrans(pBtree, 0);
+  rc = sqlite3BtreeBeginTrans(pBtree, 0, 0);
   if( rc==SQLITE_OK ){
     u8 *aData = pBt->pPage1->aData;
     if( aData[18]!=(u8)iVersion || aData[19]!=(u8)iVersion ){
-      rc = sqlite3BtreeBeginTrans(pBtree, 2);
+      rc = sqlite3BtreeBeginTrans(pBtree, 2, 0);
       if( rc==SQLITE_OK ){
         rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
         if( rc==SQLITE_OK ){
@@ -72559,7 +73232,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
     ** before this function exits.
     */
     if( rc==SQLITE_OK && 0==sqlite3BtreeIsInReadTrans(p->pSrc) ){
-      rc = sqlite3BtreeBeginTrans(p->pSrc, 0);
+      rc = sqlite3BtreeBeginTrans(p->pSrc, 0, 0);
       bCloseTrans = 1;
     }
 
@@ -72575,10 +73248,10 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
 
     /* Lock the destination database, if it is not locked already. */
     if( SQLITE_OK==rc && p->bDestLocked==0
-     && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2)) 
+     && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2,
+                                                (int*)&p->iDestSchema)) 
     ){
       p->bDestLocked = 1;
-      sqlite3BtreeGetMeta(p->pDest, BTREE_SCHEMA_VERSION, &p->iDestSchema);
     }
 
     /* Do not allow backup if the destination database is in WAL mode
@@ -73022,8 +73695,7 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){
 
   if( p->flags & MEM_Null ){
     /* Cannot be both MEM_Null and some other type */
-    assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob
-                         |MEM_RowSet|MEM_Frame|MEM_Agg))==0 );
+    assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob|MEM_Agg))==0 );
 
     /* If MEM_Null is set, then either the value is a pure NULL (the usual
     ** case) or it is a pointer set using sqlite3_bind_pointer() or
@@ -73136,7 +73808,7 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
 #ifndef SQLITE_OMIT_UTF16
   int rc;
 #endif
-  assert( (pMem->flags&MEM_RowSet)==0 );
+  assert( !sqlite3VdbeMemIsRowSet(pMem) );
   assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE
            || desiredEnc==SQLITE_UTF16BE );
   if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){
@@ -73169,7 +73841,7 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
 */
 SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
   assert( sqlite3VdbeCheckMemInvariants(pMem) );
-  assert( (pMem->flags&MEM_RowSet)==0 );
+  assert( !sqlite3VdbeMemIsRowSet(pMem) );
   testcase( pMem->db==0 );
 
   /* If the bPreserve flag is set to true, then the memory cell must already
@@ -73257,7 +73929,7 @@ static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){
 */
 SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){
   assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
-  assert( (pMem->flags&MEM_RowSet)==0 );
+  assert( !sqlite3VdbeMemIsRowSet(pMem) );
   if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){
     if( ExpandBlob(pMem) ) return SQLITE_NOMEM;
     if( pMem->szMalloc==0 || pMem->z!=pMem->zMalloc ){
@@ -73282,7 +73954,7 @@ 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( !sqlite3VdbeMemIsRowSet(pMem) );
   assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
 
   /* Set nByte to the number of bytes required to store the expanded blob. */
@@ -73337,7 +74009,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
   assert( !(fg&MEM_Zero) );
   assert( !(fg&(MEM_Str|MEM_Blob)) );
   assert( fg&(MEM_Int|MEM_Real) );
-  assert( (pMem->flags&MEM_RowSet)==0 );
+  assert( !sqlite3VdbeMemIsRowSet(pMem) );
   assert( EIGHT_BYTE_ALIGNMENT(pMem) );
 
 
@@ -73395,6 +74067,35 @@ SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
   return ctx.isError;
 }
 
+/*
+** Memory cell pAccum contains the context of an aggregate function.
+** This routine calls the xValue method for that function and stores
+** the results in memory cell pMem.
+**
+** SQLITE_ERROR is returned if xValue() reports an error. SQLITE_OK 
+** otherwise.
+*/
+#ifndef SQLITE_OMIT_WINDOWFUNC
+SQLITE_PRIVATE int sqlite3VdbeMemAggValue(Mem *pAccum, Mem *pOut, FuncDef *pFunc){
+  sqlite3_context ctx;
+  Mem t;
+  assert( pFunc!=0 );
+  assert( pFunc->xValue!=0 );
+  assert( (pAccum->flags & MEM_Null)!=0 || pFunc==pAccum->u.pDef );
+  assert( pAccum->db==0 || sqlite3_mutex_held(pAccum->db->mutex) );
+  memset(&ctx, 0, sizeof(ctx));
+  memset(&t, 0, sizeof(t));
+  t.flags = MEM_Null;
+  t.db = pAccum->db;
+  sqlite3VdbeMemSetNull(pOut);
+  ctx.pOut = pOut;
+  ctx.pMem = pAccum;
+  ctx.pFunc = pFunc;
+  pFunc->xValue(&ctx);
+  return ctx.isError;
+}
+#endif /* SQLITE_OMIT_WINDOWFUNC */
+
 /*
 ** If the memory cell contains a value that must be freed by
 ** invoking the external callback in Mem.xDel, then this routine
@@ -73413,15 +74114,8 @@ static SQLITE_NOINLINE void vdbeMemClearExternAndSetNull(Mem *p){
     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;
 }
@@ -73569,7 +74263,7 @@ SQLITE_PRIVATE int sqlite3VdbeBooleanValue(Mem *pMem, int ifNull){
 SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){
   i64 ix;
   assert( pMem->flags & MEM_Real );
-  assert( (pMem->flags & MEM_RowSet)==0 );
+  assert( !sqlite3VdbeMemIsRowSet(pMem) );
   assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
   assert( EIGHT_BYTE_ALIGNMENT(pMem) );
 
@@ -73596,7 +74290,7 @@ SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){
 */
 SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem *pMem){
   assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
-  assert( (pMem->flags & MEM_RowSet)==0 );
+  assert( !sqlite3VdbeMemIsRowSet(pMem) );
   assert( EIGHT_BYTE_ALIGNMENT(pMem) );
 
   pMem->u.i = sqlite3VdbeIntValue(pMem);
@@ -73814,26 +74508,36 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem *pMem, double val){
 }
 #endif
 
+#ifdef SQLITE_DEBUG
+/*
+** Return true if the Mem holds a RowSet object.  This routine is intended
+** for use inside of assert() statements.
+*/
+SQLITE_PRIVATE int sqlite3VdbeMemIsRowSet(const Mem *pMem){
+  return (pMem->flags&(MEM_Blob|MEM_Dyn))==(MEM_Blob|MEM_Dyn)
+         && pMem->xDel==sqlite3RowSetDelete;
+}
+#endif
+
 /*
 ** Delete any previous value and set the value of pMem to be an
 ** empty boolean index.
+**
+** Return SQLITE_OK on success and SQLITE_NOMEM if a memory allocation
+** error occurs.
 */
-SQLITE_PRIVATE void sqlite3VdbeMemSetRowSet(Mem *pMem){
+SQLITE_PRIVATE int sqlite3VdbeMemSetRowSet(Mem *pMem){
   sqlite3 *db = pMem->db;
+  RowSet *p;
   assert( db!=0 );
-  assert( (pMem->flags & MEM_RowSet)==0 );
+  assert( !sqlite3VdbeMemIsRowSet(pMem) );
   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;
-  }
+  p = sqlite3RowSetInit(db);
+  if( p==0 ) return SQLITE_NOMEM;
+  pMem->z = (char*)p;
+  pMem->flags = MEM_Blob|MEM_Dyn;
+  pMem->xDel = sqlite3RowSetDelete;
+  return SQLITE_OK;
 }
 
 /*
@@ -73866,7 +74570,21 @@ SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
   Mem *pX;
   for(i=0, pX=pVdbe->aMem; i<pVdbe->nMem; i++, pX++){
     if( pX->pScopyFrom==pMem ){
-      pX->flags |= MEM_Undefined;
+      /* If pX is marked as a shallow copy of pMem, then verify that
+      ** no significant changes have been made to pX since the OP_SCopy.
+      ** A significant change would indicated a missed call to this
+      ** function for pX.  Minor changes, such as adding or removing a
+      ** dual type, are allowed, as long as the underlying value is the
+      ** same. */
+      u16 mFlags = pMem->flags & pX->flags & pX->mScopyFlags;
+      assert( (mFlags&MEM_Int)==0 || pMem->u.i==pX->u.i );
+      assert( (mFlags&MEM_Real)==0 || pMem->u.r==pX->u.r );
+      assert( (mFlags&MEM_Str)==0  || (pMem->n==pX->n && pMem->z==pX->z) );
+      assert( (mFlags&MEM_Blob)==0  || sqlite3BlobCompare(pMem,pX)==0 );
+      
+      /* pMem is the register that is changing.  But also mark pX as
+      ** undefined so that we can quickly detect the shallow-copy error */
+      pX->flags = MEM_Undefined;
       pX->pScopyFrom = 0;
     }
   }
@@ -73887,7 +74605,7 @@ static SQLITE_NOINLINE void vdbeClrCopy(Mem *pTo, const Mem *pFrom, int eType){
   sqlite3VdbeMemShallowCopy(pTo, pFrom, eType);
 }
 SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
-  assert( (pFrom->flags & MEM_RowSet)==0 );
+  assert( !sqlite3VdbeMemIsRowSet(pFrom) );
   assert( pTo->db==pFrom->db );
   if( VdbeMemDynamic(pTo) ){ vdbeClrCopy(pTo,pFrom,srcType); return; }
   memcpy(pTo, pFrom, MEMCELLSIZE);
@@ -73905,7 +74623,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int sr
 SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
   int rc = SQLITE_OK;
 
-  assert( (pFrom->flags & MEM_RowSet)==0 );
+  assert( !sqlite3VdbeMemIsRowSet(pFrom) );
   if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo);
   memcpy(pTo, pFrom, MEMCELLSIZE);
   pTo->flags &= ~MEM_Dyn;
@@ -73963,7 +74681,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
   u16 flags = 0;      /* New value for pMem->flags */
 
   assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
-  assert( (pMem->flags & MEM_RowSet)==0 );
+  assert( !sqlite3VdbeMemIsRowSet(pMem) );
 
   /* If z is a NULL pointer, set pMem to contain an SQL NULL. */
   if( !z ){
@@ -74085,7 +74803,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(
 
   /* 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 );
+  assert( !sqlite3VdbeMemIsRowSet(pMem) );
   zData = (char *)sqlite3BtreePayloadFetch(pCur, &available);
   assert( zData!=0 );
 
@@ -74109,7 +74827,7 @@ 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( !sqlite3VdbeMemIsRowSet(pVal) );
   assert( (pVal->flags & (MEM_Null))==0 );
   if( pVal->flags & (MEM_Blob|MEM_Str) ){
     if( ExpandBlob(pVal) ) return 0;
@@ -74152,7 +74870,7 @@ 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 );
+  assert( !sqlite3VdbeMemIsRowSet(pVal) );
   if( (pVal->flags&(MEM_Str|MEM_Term))==(MEM_Str|MEM_Term) && pVal->enc==enc ){
     assert( sqlite3VdbeMemConsistentDualRep(pVal) );
     return pVal->z;
@@ -74719,11 +75437,11 @@ SQLITE_PRIVATE int sqlite3Stat4Column(
   int iCol,                       /* Column to extract */
   sqlite3_value **ppVal           /* OUT: Extracted value */
 ){
-  u32 t;                          /* a column type code */
+  u32 t = 0;                      /* 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 szField = 0;                /* 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 */
@@ -75016,14 +75734,6 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
 #endif
 #ifdef SQLITE_DEBUG
   if( p->db->flags & SQLITE_VdbeAddopTrace ){
-    int jj, kk;
-    Parse *pParse = p->pParse;
-    for(jj=kk=0; jj<pParse->nColCache; 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();
   }
@@ -75147,7 +75857,7 @@ SQLITE_PRIVATE int sqlite3VdbeExplainParent(Parse *pParse){
 SQLITE_PRIVATE void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){
   if( pParse->explain==2 ){
     char *zMsg;
-    Vdbe *v = pParse->pVdbe;
+    Vdbe *v;
     va_list ap;
     int iThis;
     va_start(ap, zFmt);
@@ -75268,19 +75978,6 @@ SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){
   }
 }
 
-#ifdef SQLITE_COVERAGE_TEST
-/*
-** Return TRUE if and only if the label x has already been resolved.
-** Return FALSE (zero) if label x is still unresolved.
-**
-** This routine is only used inside of testcase() macros, and so it
-** only exists when measuring test coverage.
-*/
-SQLITE_PRIVATE int sqlite3VdbeLabelHasBeenResolved(Vdbe *v, int x){
-  return v->pParse->aLabel && v->pParse->aLabel[ADDR(x)]>=0;
-}
-#endif /* SQLITE_COVERAGE_TEST */
-
 /*
 ** Mark the VDBE as one that can only be run one time.
 */
@@ -75512,7 +76209,6 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
           break;
         }
         case OP_Next:
-        case OP_NextIfOpen:
         case OP_SorterNext: {
           pOp->p4.xAdvance = sqlite3BtreeNext;
           pOp->p4type = P4_ADVANCE;
@@ -75522,8 +76218,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
           assert( pOp->p2>=0 );
           break;
         }
-        case OP_Prev:
-        case OP_PrevIfOpen: {
+        case OP_Prev: {
           pOp->p4.xAdvance = sqlite3BtreePrevious;
           pOp->p4type = P4_ADVANCE;
           /* The code generator never codes any of these opcodes as a jump
@@ -76438,7 +77133,7 @@ SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe *p){
 /*
 ** Print a single opcode.  This routine is used for debugging only.
 */
-SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){
+SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, VdbeOp *pOp){
   char *zP4;
   char zPtr[50];
   char zCom[100];
@@ -76507,9 +77202,8 @@ static void releaseMemArray(Mem *p, int N){
       */
       testcase( 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) ){
+      testcase( p->xDel==sqlite3VdbeFrameMemDel );
+      if( p->flags&(MEM_Agg|MEM_Dyn) ){
         sqlite3VdbeMemRelease(p);
       }else if( p->szMalloc ){
         sqlite3DbFreeNN(db, p->zMalloc);
@@ -76521,6 +77215,35 @@ static void releaseMemArray(Mem *p, int N){
   }
 }
 
+#ifdef SQLITE_DEBUG
+/*
+** Verify that pFrame is a valid VdbeFrame pointer.  Return true if it is
+** and false if something is wrong.
+**
+** This routine is intended for use inside of assert() statements only.
+*/
+SQLITE_PRIVATE int sqlite3VdbeFrameIsValid(VdbeFrame *pFrame){
+  if( pFrame->iFrameMagic!=SQLITE_FRAME_MAGIC ) return 0;
+  return 1;
+}
+#endif
+
+
+/*
+** This is a destructor on a Mem object (which is really an sqlite3_value)
+** that deletes the Frame object that is attached to it as a blob.
+**
+** This routine does not delete the Frame right away.  It merely adds the
+** frame to a list of frames to be deleted when the Vdbe halts.
+*/
+SQLITE_PRIVATE void sqlite3VdbeFrameMemDel(void *pArg){
+  VdbeFrame *pFrame = (VdbeFrame*)pArg;
+  assert( sqlite3VdbeFrameIsValid(pFrame) );
+  pFrame->pParent = pFrame->v->pDelFrame;
+  pFrame->v->pDelFrame = pFrame;
+}
+
+
 /*
 ** Delete a VdbeFrame object and its contents. VdbeFrame objects are
 ** allocated by the OP_Program opcode in sqlite3VdbeExec().
@@ -76529,6 +77252,7 @@ SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame *p){
   int i;
   Mem *aMem = VdbeFrameMem(p);
   VdbeCursor **apCsr = (VdbeCursor **)&aMem[p->nChildMem];
+  assert( sqlite3VdbeFrameIsValid(p) );
   for(i=0; i<p->nChildCsr; i++){
     sqlite3VdbeFreeCursor(p->v, apCsr[i]);
   }
@@ -77825,7 +78549,7 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
   */
   sqlite3VdbeHalt(p);
 
-  /* If the VDBE has be run even partially, then transfer the error code
+  /* If the VDBE has been run even partially, then transfer the error code
   ** and error message from the VDBE into the main database structure.  But
   ** if the VDBE has just been set to run but has not actually executed any
   ** instructions yet, leave the main database error information unchanged.
@@ -78737,7 +79461,7 @@ static int isAllZero(const char *z, int n){
 ** is less than, equal to, or greater than the second, respectively.
 ** If one blob is a prefix of the other, then the shorter is the lessor.
 */
-static SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){
+SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){
   int c;
   int n1 = pB1->n;
   int n2 = pB2->n;
@@ -78807,7 +79531,7 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C
   f1 = pMem1->flags;
   f2 = pMem2->flags;
   combined_flags = f1|f2;
-  assert( (combined_flags & MEM_RowSet)==0 );
+  assert( !sqlite3VdbeMemIsRowSet(pMem1) && !sqlite3VdbeMemIsRowSet(pMem2) );
  
   /* If one value is NULL, it is less than the other. If both values
   ** are NULL, return 0.
@@ -78952,7 +79676,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
   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;
+  KeyInfo *pKeyInfo;
   const unsigned char *aKey1 = (const unsigned char *)pKey1;
   Mem mem1;
 
@@ -79047,7 +79771,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
         if( (d1+mem1.n) > (unsigned)nKey1 ){
           pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
           return 0;                /* Corruption */
-        }else if( pKeyInfo->aColl[i] ){
+        }else if( (pKeyInfo = pPKey2->pKeyInfo)->aColl[i] ){
           mem1.enc = pKeyInfo->enc;
           mem1.db = pKeyInfo->db;
           mem1.flags = MEM_Str;
@@ -79098,7 +79822,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
     }
 
     if( rc!=0 ){
-      if( pKeyInfo->aSortOrder[i] ){
+      if( pPKey2->pKeyInfo->aSortOrder[i] ){
         rc = -rc;
       }
       assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, rc) );
@@ -79107,10 +79831,11 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
     }
 
     i++;
+    if( i==pPKey2->nField ) break;
     pRhs++;
     d1 += sqlite3VdbeSerialTypeLen(serial_type);
     idx1 += sqlite3VarintLen(serial_type);
-  }while( idx1<(unsigned)szHdr1 && i<pPKey2->nField && d1<=(unsigned)nKey1 );
+  }while( idx1<(unsigned)szHdr1 && d1<=(unsigned)nKey1 );
 
   /* No memory allocation is ever used on mem1.  Prove this using
   ** the following assert().  If the assert() fails, it indicates a
@@ -79122,7 +79847,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
   ** value.  */
   assert( CORRUPT_DB 
        || vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, pPKey2->default_rc) 
-       || pKeyInfo->db->mallocFailed
+       || pPKey2->pKeyInfo->db->mallocFailed
   );
   pPKey2->eqSeen = 1;
   return pPKey2->default_rc;
@@ -79448,7 +80173,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
   if( rc ){
     return rc;
   }
-  *res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked);
+  *res = sqlite3VdbeRecordCompareWithSkip(m.n, m.z, pUnpacked, 0);
   sqlite3VdbeMemRelease(&m);
   return SQLITE_OK;
 }
@@ -79480,11 +80205,19 @@ SQLITE_PRIVATE void sqlite3VdbeCountChanges(Vdbe *v){
 ** programs obsolete.  Removing user-defined functions or collating
 ** sequences, or changing an authorization function are the types of
 ** things that make prepared statements obsolete.
+**
+** If iCode is 1, then expiration is advisory.  The statement should
+** be reprepared before being restarted, but if it is already running
+** it is allowed to run to completion.
+**
+** Internally, this function just sets the Vdbe.expired flag on all
+** prepared statements.  The flag is set to 1 for an immediate expiration
+** and set to 2 for an advisory expiration.
 */
-SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3 *db){
+SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3 *db, int iCode){
   Vdbe *p;
   for(p = db->pVdbe; p; p=p->pNext){
-    p->expired = 1;
+    p->expired = iCode+1;
   }
 }
 
@@ -80644,7 +81377,7 @@ static const Mem *columnNullValue(void){
         /* .xDel       = */ (void(*)(void*))0,
 #ifdef SQLITE_DEBUG
         /* .pScopyFrom = */ (Mem*)0,
-        /* .pFiller    = */ (void*)0,
+        /* .mScopyFlags= */ 0,
 #endif
       };
   return &nullMem;
@@ -81954,32 +82687,56 @@ SQLITE_API int sqlite3_found_count = 0;
 ** 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.
+** M is an integer between 2 and 4.  2 indicates a ordinary two-way
+** branch (I=0 means fall through and I=1 means taken).  3 indicates
+** a 3-way branch where the third way is when one of the operands is
+** NULL.  4 indicates the OP_Jump instruction which has three destinations
+** depending on whether the first operand is less than, equal to, or greater
+** than the second. 
 **
 ** 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.
+** generated the VDBE instruction combined with flag bits.  The source
+** code line number is in the lower 24 bits of iSrcLine and the upper
+** 8 bytes are flags.  The lower three bits of the flags indicate
+** values for I that should never occur.  For example, if the branch is
+** always taken, the flags should be 0x05 since the fall-through and
+** alternate branch are never taken.  If a branch is never taken then
+** flags should be 0x06 since only the fall-through approach is allowed.
+**
+** Bit 0x04 of the flags indicates an OP_Jump opcode that is only
+** interested in equal or not-equal.  In other words, I==0 and I==2
+** should be treated the same.
+**
+** Since only a line number is retained, not the filename, this macro
+** only works for amalgamation builds.  But that is ok, since these macros
+** should be no-ops except for special builds used to measure test coverage.
 */
 #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);
-    }
+  static void vdbeTakeBranch(u32 iSrcLine, u8 I, u8 M){
+    u8 mNever;
+    assert( I<=2 );  /* 0: fall through,  1: taken,  2: alternate taken */
+    assert( M<=4 );  /* 2: two-way branch, 3: three-way branch, 4: OP_Jump */
+    assert( I<M );   /* I can only be 2 if M is 3 or 4 */
+    /* Transform I from a integer [0,1,2] into a bitmask of [1,2,4] */
+    I = 1<<I;
+    /* The upper 8 bits of iSrcLine are flags.  The lower three bits of
+    ** the flags indicate directions that the branch can never go.  If
+    ** a branch really does go in one of those directions, assert right
+    ** away. */
+    mNever = iSrcLine >> 24;
+    assert( (I & mNever)==0 );
+    if( sqlite3GlobalConfig.xVdbeBranch==0 ) return;  /*NO_TEST*/
+    I |= mNever;
+    if( M==2 ) I |= 0x04;
+    if( M==4 ){
+      I |= 0x08;
+      if( (mNever&0x08)!=0 && (I&0x05)!=0) I |= 0x05; /*NO_TEST*/
+    }
+    sqlite3GlobalConfig.xVdbeBranch(sqlite3GlobalConfig.pVdbeBranchArg,
+                                    iSrcLine&0xffffff, I, M);
   }
 #endif
 
@@ -82310,7 +83067,7 @@ static void memTracePrint(Mem *p){
   }else if( p->flags & MEM_Real ){
     printf(" r:%g", p->u.r);
 #endif
-  }else if( p->flags & MEM_RowSet ){
+  }else if( sqlite3VdbeMemIsRowSet(p) ){
     printf(" (rowset)");
   }else{
     char zBuf[200];
@@ -83064,6 +83821,9 @@ case OP_Null: {           /* out2 */
   assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
   pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null;
   pOut->n = 0;
+#ifdef SQLITE_DEBUG
+  pOut->uTemp = 0;
+#endif
   while( cnt>0 ){
     pOut++;
     memAboutToChange(p, pOut);
@@ -83185,6 +83945,7 @@ case OP_Copy: {
   pOut = &aMem[pOp->p2];
   assert( pOut!=pIn1 );
   while( 1 ){
+    memAboutToChange(p, pOut);
     sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem);
     Deephemeralize(pOut);
 #ifdef SQLITE_DEBUG
@@ -83217,7 +83978,8 @@ case OP_SCopy: {            /* out2 */
   assert( pOut!=pIn1 );
   sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem);
 #ifdef SQLITE_DEBUG
-  if( pOut->pScopyFrom==0 ) pOut->pScopyFrom = pIn1;
+  pOut->pScopyFrom = pIn1;
+  pOut->mScopyFlags = pIn1->flags;
 #endif
   break;
 }
@@ -83851,7 +84613,12 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
       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 */
+          assert( flags3==pIn3->flags );
+          /* testcase( flags3!=pIn3->flags );
+          ** this used to be possible with pIn1==pIn3, but not since
+          ** the column cache was removed.  The following assignment
+          ** is essentially a no-op.  But, it provides defense-in-depth
+          ** in case our analysis is incorrect, so it is left in. */
           flags3 = pIn3->flags;
         }
         if( (flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
@@ -84065,11 +84832,11 @@ case OP_Compare: {
 */
 case OP_Jump: {             /* jump */
   if( iCompare<0 ){
-    VdbeBranchTaken(0,3); pOp = &aOp[pOp->p1 - 1];
+    VdbeBranchTaken(0,4); pOp = &aOp[pOp->p1 - 1];
   }else if( iCompare==0 ){
-    VdbeBranchTaken(1,3); pOp = &aOp[pOp->p2 - 1];
+    VdbeBranchTaken(1,4); pOp = &aOp[pOp->p2 - 1];
   }else{
-    VdbeBranchTaken(2,3); pOp = &aOp[pOp->p3 - 1];
+    VdbeBranchTaken(2,4); pOp = &aOp[pOp->p3 - 1];
   }
   break;
 }
@@ -84166,7 +84933,7 @@ case OP_Not: {                /* same as TK_NOT, in1, out2 */
 }
 
 /* Opcode: BitNot P1 P2 * * *
-** Synopsis: r[P1]= ~r[P1]
+** Synopsis: r[P2]= ~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
@@ -84981,7 +85748,7 @@ case OP_Savepoint: {
           }
         }
         if( isSchemaChange ){
-          sqlite3ExpirePreparedStatements(db);
+          sqlite3ExpirePreparedStatements(db, 0);
           sqlite3ResetAllSchemasOfConnection(db);
           db->mDbFlags |= DBFLAG_SchemaChange;
         }
@@ -85123,8 +85890,7 @@ case OP_AutoCommit: {
 */
 case OP_Transaction: {
   Btree *pBt;
-  int iMeta;
-  int iGen;
+  int iMeta = 0;
 
   assert( p->bIsReader );
   assert( p->readOnly==0 || pOp->p2==0 );
@@ -85137,7 +85903,7 @@ case OP_Transaction: {
   pBt = db->aDb[pOp->p1].pBt;
 
   if( pBt ){
-    rc = sqlite3BtreeBeginTrans(pBt, pOp->p2);
+    rc = sqlite3BtreeBeginTrans(pBt, pOp->p2, &iMeta);
     testcase( rc==SQLITE_BUSY_SNAPSHOT );
     testcase( rc==SQLITE_BUSY_RECOVERY );
     if( rc!=SQLITE_OK ){
@@ -85170,19 +85936,17 @@ case OP_Transaction: {
       p->nStmtDefCons = db->nDeferredCons;
       p->nStmtDefImmCons = db->nDeferredImmCons;
     }
-
-    /* Gather the schema version number for checking:
+  }
+  assert( pOp->p5==0 || pOp->p4type==P4_INT32 );
+  if( pOp->p5
+   && (iMeta!=pOp->p3
+      || db->aDb[pOp->p1].pSchema->iGeneration!=pOp->p4.i)
+  ){
+    /*
     ** 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 
@@ -85273,7 +86037,7 @@ case OP_SetCookie: {
   if( pOp->p1==1 ){
     /* Invalidate all prepared statements whenever the TEMP database
     ** schema is changed.  Ticket #1644 */
-    sqlite3ExpirePreparedStatements(db);
+    sqlite3ExpirePreparedStatements(db, 0);
     p->expired = 0;
   }
   if( rc ) goto abort_due_to_error;
@@ -85291,59 +86055,78 @@ case OP_SetCookie: {
 ** 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.
+** Allowed P5 bits:
+** <ul>
+** <li>  <b>0x02 OPFLAG_SEEKEQ</b>: This cursor will only be used for
+**       equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT
+**       of OP_SeekLE/OP_IdxGT)
+** </ul>
 **
 ** The P4 value may be either an integer (P4_INT32) or a pointer to
 ** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo 
-** 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.
+** object, then table being opened must be an [index b-tree] where the
+** KeyInfo object defines the content and collating 
+** sequence of that index b-tree. Otherwise, if P4 is an integer 
+** value, then the table being opened must be a [table b-tree] with a
+** number of columns no less than the value of P4.
 **
 ** 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,
+** The ReopenIdx opcode works like OP_OpenRead except that it first
+** checks to see if the cursor on P1 is already open on the same
+** b-tree 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.
+** The ReopenIdx opcode may only be used with P5==0 or P5==OPFLAG_SEEKEQ
+** 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.
+**
+** Allowed P5 bits:
+** <ul>
+** <li>  <b>0x02 OPFLAG_SEEKEQ</b>: This cursor will only be used for
+**       equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT
+**       of OP_SeekLE/OP_IdxGT)
+** </ul>
 **
-** See the OpenRead opcode documentation for additional information.
+** See also: OP_OpenRead, OP_OpenWrite
 */
 /* 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.
+** page is P2 (or whose root page is held in register P2 if the
+** OPFLAG_P2ISREG bit is set in P5 - see below).
 **
 ** The P4 value may be either an integer (P4_INT32) or a pointer to
 ** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo 
-** 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.
+** object, then table being opened must be an [index b-tree] where the
+** KeyInfo object defines the content and collating 
+** sequence of that index b-tree. Otherwise, if P4 is an integer 
+** value, then the table being opened must be a [table b-tree] with a
+** number of columns no less than the value of P4.
+**
+** Allowed P5 bits:
+** <ul>
+** <li>  <b>0x02 OPFLAG_SEEKEQ</b>: This cursor will only be used for
+**       equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT
+**       of OP_SeekLE/OP_IdxGT)
+** <li>  <b>0x08 OPFLAG_FORDELETE</b>: This cursor is used only to seek
+**       and subsequently delete entries in an index btree.  This is a
+**       hint to the storage engine that the storage engine is allowed to
+**       ignore.  The hint is not used by the official SQLite b*tree storage
+**       engine, but is used by COMDB2.
+** <li>  <b>0x10 OPFLAG_P2ISREG</b>: Use the content of register P2
+**       as the root page, not the value of P2 itself.
+** </ul>
 **
-** 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.
+** This instruction works like OpenRead except that it opens the cursor
+** in read/write mode.
 **
-** See also OpenRead.
+** See also: OP_OpenRead, OP_ReopenIdx
 */
 case OP_ReopenIdx: {
   int nField;
@@ -85372,7 +86155,7 @@ case OP_OpenWrite:
   assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx
           || p->readOnly==0 );
 
-  if( p->expired ){
+  if( p->expired==1 ){
     rc = SQLITE_ABORT_ROLLBACK;
     goto abort_due_to_error;
   }
@@ -85399,6 +86182,7 @@ case OP_OpenWrite:
   if( pOp->p5 & OPFLAG_P2ISREG ){
     assert( p2>0 );
     assert( p2<=(p->nMem+1 - p->nCursor) );
+    assert( pOp->opcode==OP_OpenWrite );
     pIn2 = &aMem[p2];
     assert( memIsValid(pIn2) );
     assert( (pIn2->flags & MEM_Int)!=0 );
@@ -85527,7 +86311,7 @@ case OP_OpenEphemeral: {
   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);
+    rc = sqlite3BtreeBeginTrans(pCx->pBtx, 1, 0);
   }
   if( rc==SQLITE_OK ){
     /* If a transient index is required, create it by calling
@@ -85754,10 +86538,10 @@ case OP_ColumnsUsed: {
 **
 ** 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 */
+case OP_SeekLT:         /* jump, in3, group */
+case OP_SeekLE:         /* jump, in3, group */
+case OP_SeekGE:         /* jump, in3, group */
+case OP_SeekGT: {       /* jump, in3, group */
   int res;           /* Comparison result */
   int oc;            /* Opcode */
   VdbeCursor *pC;    /* The cursor to seek */
@@ -85935,6 +86719,25 @@ seek_not_found:
   break;
 }
 
+/* Opcode: SeekHit P1 P2 * * *
+** Synopsis: seekHit=P2
+**
+** Set the seekHit flag on cursor P1 to the value in P2.
+** The seekHit flag is used by the IfNoHope opcode.
+**
+** P1 must be a valid b-tree cursor.  P2 must be a boolean value,
+** either 0 or 1.
+*/
+case OP_SeekHit: {
+  VdbeCursor *pC;
+  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+  pC = p->apCsr[pOp->p1];
+  assert( pC!=0 );
+  assert( pOp->p2==0 || pOp->p2==1 );
+  pC->seekHit = pOp->p2 & 1;
+  break;
+}
+
 /* Opcode: Found P1 P2 P3 P4 *
 ** Synopsis: key=r[P3@P4]
 **
@@ -85969,7 +86772,34 @@ seek_not_found:
 ** advanced in either direction.  In other words, the Next and Prev
 ** opcodes do not work after this operation.
 **
-** See also: Found, NotExists, NoConflict
+** See also: Found, NotExists, NoConflict, IfNoHope
+*/
+/* Opcode: IfNoHope P1 P2 P3 P4 *
+** Synopsis: key=r[P3@P4]
+**
+** Register P3 is the first of P4 registers that form an unpacked
+** record.
+**
+** Cursor P1 is on an index btree.  If the seekHit flag is set on P1, then
+** this opcode is a no-op.  But if the seekHit flag of P1 is clear, then
+** check to see if there is any entry in P1 that matches the
+** prefix identified by P3 and P4.  If no entry matches the prefix,
+** jump to P2.  Otherwise fall through.
+**
+** This opcode behaves like OP_NotFound if the seekHit
+** flag is clear and it behaves like OP_Noop if the seekHit flag is set.
+**
+** This opcode is used in IN clause processing for a multi-column key.
+** If an IN clause is attached to an element of the key other than the
+** left-most element, and if there are no matches on the most recent
+** seek over the whole key, then it might be that one of the key element
+** to the left is prohibiting a match, and hence there is "no hope" of
+** any match regardless of how many IN clause elements are checked.
+** In such a case, we abandon the IN clause search early, using this
+** opcode.  The opcode name comes from the fact that the
+** jump is taken if there is "no hope" of achieving a match.
+**
+** See also: NotFound, SeekHit
 */
 /* Opcode: NoConflict P1 P2 P3 P4 *
 ** Synopsis: key=r[P3@P4]
@@ -85994,6 +86824,14 @@ seek_not_found:
 **
 ** See also: NotFound, Found, NotExists
 */
+case OP_IfNoHope: {     /* jump, in3 */
+  VdbeCursor *pC;
+  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+  pC = p->apCsr[pOp->p1];
+  assert( pC!=0 );
+  if( pC->seekHit ) break;
+  /* Fall through into OP_NotFound */
+}
 case OP_NoConflict:     /* jump, in3 */
 case OP_NotFound:       /* jump, in3 */
 case OP_Found: {        /* jump, in3 */
@@ -86131,18 +86969,26 @@ case OP_SeekRowid: {        /* jump, in3 */
 
   pIn3 = &aMem[pOp->p3];
   if( (pIn3->flags & MEM_Int)==0 ){
+    /* Make sure pIn3->u.i contains a valid integer representation of
+    ** the key value, but do not change the datatype of the register, as
+    ** other parts of the perpared statement might be depending on the
+    ** current datatype. */
+    u16 origFlags = pIn3->flags;
+    int isNotInt;
     applyAffinity(pIn3, SQLITE_AFF_NUMERIC, encoding);
-    if( (pIn3->flags & MEM_Int)==0 ) goto jump_to_p2;
+    isNotInt = (pIn3->flags & MEM_Int)==0;
+    pIn3->flags = origFlags;
+    if( isNotInt ) goto jump_to_p2;
   }
   /* Fall through into OP_NotExists */
 case OP_NotExists:          /* jump, in3 */
   pIn3 = &aMem[pOp->p3];
-  assert( pIn3->flags & MEM_Int );
+  assert( (pIn3->flags & MEM_Int)!=0 || pOp->opcode==OP_SeekRowid );
   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
   pC = p->apCsr[pOp->p1];
   assert( pC!=0 );
 #ifdef SQLITE_DEBUG
-  pC->seekOp = 0;
+  pC->seekOp = OP_SeekRowid;
 #endif
   assert( pC->isTable );
   assert( pC->eCurType==CURTYPE_BTREE );
@@ -86796,6 +87642,9 @@ case OP_NullRow: {
     assert( pC->uc.pCursor!=0 );
     sqlite3BtreeClearCursor(pC->uc.pCursor);
   }
+#ifdef SQLITE_DEBUG
+  if( pC->seekOp==0 ) pC->seekOp = OP_NullRow;
+#endif
   break;
 }
 
@@ -86914,7 +87763,7 @@ case OP_Sort: {        /* jump */
   p->aCounter[SQLITE_STMTSTATUS_SORT]++;
   /* Fall through into OP_Rewind */
 }
-/* Opcode: Rewind P1 P2 * * *
+/* Opcode: Rewind P1 P2 * * P5
 **
 ** 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.
@@ -86922,6 +87771,10 @@ case OP_Sort: {        /* jump */
 ** If the table or index is not empty, fall through to the following 
 ** instruction.
 **
+** If P5 is non-zero and the table is not empty, then the "skip-next"
+** flag is set on the cursor so that the next OP_Next instruction 
+** executed on it is a no-op.
+**
 ** 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.
@@ -86946,6 +87799,9 @@ case OP_Rewind: {        /* jump */
     pCrsr = pC->uc.pCursor;
     assert( pCrsr );
     rc = sqlite3BtreeFirst(pCrsr, &res);
+#ifndef SQLITE_OMIT_WINDOWFUNC
+    if( pOp->p5 ) sqlite3BtreeSkipNext(pCrsr);
+#endif
     pC->deferredMoveto = 0;
     pC->cacheStatus = CACHE_STALE;
   }
@@ -86982,12 +87838,7 @@ case OP_Rewind: {        /* jump */
 ** 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.
+** See also: Prev
 */
 /* Opcode: Prev P1 P2 P3 P4 P5
 **
@@ -87015,11 +87866,6 @@ case OP_Rewind: {        /* jump */
 ** 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
@@ -87034,10 +87880,6 @@ case OP_SorterNext: {  /* jump */
   assert( isSorter(pC) );
   rc = sqlite3VdbeSorterNext(db, pC);
   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->p1<p->nCursor );
@@ -87048,17 +87890,17 @@ case OP_Next:          /* jump */
   assert( pC->eCurType==CURTYPE_BTREE );
   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 Next opcode is only used after SeekGT, SeekGE, Rewind, and Found.
   ** The Prev opcode is only used after SeekLT, SeekLE, and Last. */
-  assert( pOp->opcode!=OP_Next || pOp->opcode!=OP_NextIfOpen
+  assert( pOp->opcode!=OP_Next
        || 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_Rewind || pC->seekOp==OP_Found 
+       || pC->seekOp==OP_NullRow);
+  assert( pOp->opcode!=OP_Prev
        || pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE
-       || pC->seekOp==OP_Last );
+       || pC->seekOp==OP_Last 
+       || pC->seekOp==OP_NullRow);
 
   rc = pOp->p4.xAdvance(pC->uc.pCursor, pOp->p3);
 next_tail:
@@ -87341,7 +88183,13 @@ case OP_IdxGE:  {       /* jump */
   }
   r.aMem = &aMem[pOp->p3];
 #ifdef SQLITE_DEBUG
-  { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
+  {
+    int i;
+    for(i=0; i<r.nField; i++){
+      assert( memIsValid(&r.aMem[i]) );
+      REGISTER_TRACE(pOp->p3+i, &aMem[pOp->p3+i]);
+    }
+  }
 #endif
   res = 0;  /* Not needed.  Only used to silence a warning. */
   rc = sqlite3VdbeIdxKeyCompare(db, pC, &r, &res);
@@ -87528,7 +88376,8 @@ case OP_SqlExec: {
 /* Opcode: ParseSchema P1 * * P4 *
 **
 ** Read and parse all entries from the SQLITE_MASTER table of database P1
-** that match the WHERE clause P4. 
+** that match the WHERE clause P4.  If P4 is a NULL pointer, then the
+** entire schema for P1 is reparsed.
 **
 ** This opcode invokes the parser to create a new virtual machine,
 ** then runs the new virtual machine.  It is thus a re-entrant opcode.
@@ -87552,11 +88401,22 @@ case OP_ParseSchema: {
   iDb = pOp->p1;
   assert( iDb>=0 && iDb<db->nDb );
   assert( DbHasProperty(db, iDb, DB_SchemaLoaded) );
-  /* Used to be a conditional */ {
+
+#ifndef SQLITE_OMIT_ALTERTABLE
+  if( pOp->p4.z==0 ){
+    sqlite3SchemaClear(db->aDb[iDb].pSchema);
+    db->mDbFlags &= ~DBFLAG_SchemaKnownOk;
+    rc = sqlite3InitOne(db, iDb, &p->zErrMsg, INITFLAG_AlterTable);
+    db->mDbFlags |= DBFLAG_SchemaChange;
+    p->expired = 0;
+  }else
+#endif
+  {
     zMaster = MASTER_NAME;
     initData.db = db;
     initData.iDb = pOp->p1;
     initData.pzErrMsg = &p->zErrMsg;
+    initData.mInitFlags = 0;
     zSql = sqlite3MPrintf(db,
        "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid",
        db->aDb[iDb].zDbSName, zMaster, pOp->p4.z);
@@ -87709,11 +88569,11 @@ 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;
+  if( (pIn1->flags & MEM_Blob)==0 ){
+    if( sqlite3VdbeMemSetRowSet(pIn1) ) goto no_mem;
   }
-  sqlite3RowSetInsert(pIn1->u.pRowSet, pIn2->u.i);
+  assert( sqlite3VdbeMemIsRowSet(pIn1) );
+  sqlite3RowSetInsert((RowSet*)pIn1->z, pIn2->u.i);
   break;
 }
 
@@ -87729,8 +88589,9 @@ case OP_RowSetRead: {       /* jump, in1, out3 */
   i64 val;
 
   pIn1 = &aMem[pOp->p1];
-  if( (pIn1->flags & MEM_RowSet)==0 
-   || sqlite3RowSetNext(pIn1->u.pRowSet, &val)==0
+  assert( (pIn1->flags & MEM_Blob)==0 || sqlite3VdbeMemIsRowSet(pIn1) );
+  if( (pIn1->flags & MEM_Blob)==0 
+   || sqlite3RowSetNext((RowSet*)pIn1->z, &val)==0
   ){
     /* The boolean index is empty */
     sqlite3VdbeMemSetNull(pIn1);
@@ -87779,20 +88640,19 @@ case OP_RowSetTest: {                     /* jump, in1, in3 */
   /* 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;
+  if( (pIn1->flags & MEM_Blob)==0 ){
+    if( sqlite3VdbeMemSetRowSet(pIn1) ) goto no_mem;
   }
-
+  assert( sqlite3VdbeMemIsRowSet(pIn1) );
   assert( pOp->p4type==P4_INT32 );
   assert( iSet==-1 || iSet>=0 );
   if( iSet ){
-    exists = sqlite3RowSetTest(pIn1->u.pRowSet, iSet, pIn3->u.i);
+    exists = sqlite3RowSetTest((RowSet*)pIn1->z, iSet, pIn3->u.i);
     VdbeBranchTaken(exists!=0,2);
     if( exists ) goto jump_to_p2;
   }
   if( iSet>=0 ){
-    sqlite3RowSetInsert(pIn1->u.pRowSet, pIn3->u.i);
+    sqlite3RowSetInsert((RowSet*)pIn1->z, pIn3->u.i);
   }
   break;
 }
@@ -87856,7 +88716,7 @@ case OP_Program: {        /* jump */
   ** 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 ){
+  if( (pRt->flags&MEM_Blob)==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
@@ -87874,8 +88734,10 @@ case OP_Program: {        /* jump */
       goto no_mem;
     }
     sqlite3VdbeMemRelease(pRt);
-    pRt->flags = MEM_Frame;
-    pRt->u.pFrame = pFrame;
+    pRt->flags = MEM_Blob|MEM_Dyn;
+    pRt->z = (char*)pFrame;
+    pRt->n = nByte;
+    pRt->xDel = sqlite3VdbeFrameMemDel;
 
     pFrame->v = p;
     pFrame->nChildMem = nMem;
@@ -87891,6 +88753,9 @@ case OP_Program: {        /* jump */
 #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
     pFrame->anExec = p->anExec;
 #endif
+#ifdef SQLITE_DEBUG
+    pFrame->iFrameMagic = SQLITE_FRAME_MAGIC;
+#endif
 
     pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem];
     for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){
@@ -87898,7 +88763,8 @@ case OP_Program: {        /* jump */
       pMem->db = db;
     }
   }else{
-    pFrame = pRt->u.pFrame;
+    pFrame = (VdbeFrame*)pRt->z;
+    assert( pRt->xDel==sqlite3VdbeFrameMemDel );
     assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem 
         || (pProgram->nCsr==0 && pProgram->nMem+1==pFrame->nChildMem) );
     assert( pProgram->nCsr==pFrame->nChildCsr );
@@ -88127,24 +88993,35 @@ case OP_DecrJumpZero: {      /* jump, in1 */
 }
 
 
-/* Opcode: AggStep0 * P2 P3 P4 P5
+/* 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 the FuncDef
-** structure that specifies the function.  Register P3 is the
+** Execute the xStep 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
+/* Opcode: AggInverse * P2 P3 P4 P5
+** Synopsis: accum=r[P3] inverse(r[P2@P5])
+**
+** Execute the xInverse function for an aggregate.
+** The function has P5 arguments.  P4 is a pointer to the 
+** FuncDef structure that specifies the function.  Register P3 is the
+** accumulator.
+**
+** The P5 arguments are taken from register P2 and its
+** successors.
+*/
+/* Opcode: AggStep1 P1 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.
+** Execute the xStep (if P1==0) or xInverse (if P1!=0) function for an
+** aggregate.  The function has P5 arguments.  P4 is a pointer to the 
+** FuncDef structure that specifies the function.  Register P3 is the
+** accumulator.
 **
 ** The P5 arguments are taken from register P2 and its
 ** successors.
@@ -88155,7 +89032,8 @@ case OP_DecrJumpZero: {      /* jump, in1 */
 ** sqlite3_context only happens once, instead of on each call to the
 ** step function.
 */
-case OP_AggStep0: {
+case OP_AggInverse:
+case OP_AggStep: {
   int n;
   sqlite3_context *pCtx;
 
@@ -88178,10 +89056,14 @@ case OP_AggStep0: {
   pCtx->argc = n;
   pOp->p4type = P4_FUNCCTX;
   pOp->p4.pCtx = pCtx;
-  pOp->opcode = OP_AggStep;
+
+  /* OP_AggInverse must have P1==1 and OP_AggStep must have P1==0 */
+  assert( pOp->p1==(pOp->opcode==OP_AggInverse) );
+
+  pOp->opcode = OP_AggStep1;
   /* Fall through into OP_AggStep */
 }
-case OP_AggStep: {
+case OP_AggStep1: {
   int i;
   sqlite3_context *pCtx;
   Mem *pMem;
@@ -88190,6 +89072,17 @@ case OP_AggStep: {
   pCtx = pOp->p4.pCtx;
   pMem = &aMem[pOp->p3];
 
+#ifdef SQLITE_DEBUG
+  if( pOp->p1 ){
+    /* This is an OP_AggInverse call.  Verify that xStep has always
+    ** been called at least once prior to any xInverse call. */
+    assert( pMem->uTemp==0x1122e0e3 );
+  }else{
+    /* This is an OP_AggStep call.  Mark it as such. */
+    pMem->uTemp = 0x1122e0e3;
+  }
+#endif
+
   /* 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
@@ -88210,7 +89103,13 @@ case OP_AggStep: {
   assert( pCtx->pOut->flags==MEM_Null );
   assert( pCtx->isError==0 );
   assert( pCtx->skipFlag==0 );
+#ifndef SQLITE_OMIT_WINDOWFUNC
+  if( pOp->p1 ){
+    (pCtx->pFunc->xInverse)(pCtx,pCtx->argc,pCtx->argv);
+  }else
+#endif
   (pCtx->pFunc->xSFunc)(pCtx,pCtx->argc,pCtx->argv); /* IMP: R-24505-23230 */
+
   if( pCtx->isError ){
     if( pCtx->isError>0 ){
       sqlite3VdbeError(p, "%s", sqlite3_value_text(pCtx->pOut));
@@ -88235,22 +89134,46 @@ case OP_AggStep: {
 /* 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.
+** P1 is the memory location that is the accumulator for an aggregate
+** or window function.  Execute the finalizer function 
+** for an aggregate and store the result in P1.
 **
 ** P2 is the number of arguments that the step function takes and
 ** 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
+** P4 argument is only needed for the case where
 ** the step function was not previously called.
 */
+/* Opcode: AggValue * P2 P3 P4 *
+** Synopsis: r[P3]=value N=P2
+**
+** Invoke the xValue() function and store the result in register P3.
+**
+** 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 case where
+** the step function was not previously called.
+*/
+case OP_AggValue:
 case OP_AggFinal: {
   Mem *pMem;
   assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
+  assert( pOp->p3==0 || pOp->opcode==OP_AggValue );
   pMem = &aMem[pOp->p1];
   assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
-  rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc);
+#ifndef SQLITE_OMIT_WINDOWFUNC
+  if( pOp->p3 ){
+    rc = sqlite3VdbeMemAggValue(pMem, &aMem[pOp->p3], pOp->p4.pFunc);
+    pMem = &aMem[pOp->p3];
+  }else
+#endif
+  {
+    rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc);
+  }
+  
   if( rc ){
     sqlite3VdbeError(p, "%s", sqlite3_value_text(pMem));
     goto abort_due_to_error;
@@ -88445,7 +89368,7 @@ case OP_IncrVacuum: {        /* jump */
 }
 #endif
 
-/* Opcode: Expire P1 * * * *
+/* Opcode: Expire P1 P2 * * *
 **
 ** Cause precompiled statements to expire.  When an expired statement
 ** is executed using sqlite3_step() it will either automatically
@@ -88454,12 +89377,19 @@ case OP_IncrVacuum: {        /* jump */
 ** 
 ** If P1 is 0, then all SQL statements become expired. If P1 is non-zero,
 ** then only the currently executing statement is expired.
+**
+** If P2 is 0, then SQL statements are expired immediately.  If P2 is 1,
+** then running SQL statements are allowed to continue to run to completion.
+** The P2==1 case occurs when a CREATE INDEX or similar schema change happens
+** that might help the statement run faster but which does not affect the
+** correctness of operation.
 */
 case OP_Expire: {
+  assert( pOp->p2==0 || pOp->p2==1 );
   if( !pOp->p1 ){
-    sqlite3ExpirePreparedStatements(db);
+    sqlite3ExpirePreparedStatements(db, pOp->p2);
   }else{
-    p->expired = 1;
+    p->expired = pOp->p2+1;
   }
   break;
 }
@@ -88845,6 +89775,7 @@ case OP_VUpdate: {
        || pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace
   );
   assert( p->readOnly==0 );
+  if( db->mallocFailed ) goto no_mem;
   sqlite3VdbeIncrWriteCounter(p, 0);
   pVtab = pOp->p4.pVtab->pVtab;
   if( pVtab==0 || NEVER(pVtab->pModule==0) ){
@@ -88966,8 +89897,8 @@ case OP_MaxPgcnt: {            /* out2 */
 **
 ** See also: Function0, AggStep, AggFinal
 */
-case OP_PureFunc0:
-case OP_Function0: {
+case OP_PureFunc0:              /* group */
+case OP_Function0: {            /* group */
   int n;
   sqlite3_context *pCtx;
 
@@ -88991,8 +89922,8 @@ case OP_Function0: {
   pOp->opcode += 2;
   /* Fall through into OP_Function */
 }
-case OP_PureFunc:
-case OP_Function: {
+case OP_PureFunc:              /* group */
+case OP_Function: {            /* group */
   int i;
   sqlite3_context *pCtx;
 
@@ -91917,7 +92848,11 @@ static int vdbeMergeEngineInit(
 ){
   int rc = SQLITE_OK;             /* Return code */
   int i;                          /* For looping over PmaReader objects */
-  int nTree = pMerger->nTree;
+  int nTree;                      /* Number of subtrees to merge */
+
+  /* Failure to allocate the merge would have been detected prior to
+  ** invoking this routine */
+  assert( pMerger!=0 );
 
   /* eMode is always INCRINIT_NORMAL in single-threaded mode */
   assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL );
@@ -91926,6 +92861,7 @@ static int vdbeMergeEngineInit(
   assert( pMerger->pTask==0 );
   pMerger->pTask = pTask;
 
+  nTree = pMerger->nTree;
   for(i=0; i<nTree; i++){
     if( SQLITE_MAX_WORKER_THREADS>0 && eMode==INCRINIT_ROOT ){
       /* PmaReaders should be normally initialized in order, as if they are
@@ -93054,6 +93990,14 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
       }else if( pExpr->x.pList ){
         if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
       }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+      if( !ExprHasProperty(pExpr, EP_Reduced) && pExpr->pWin ){
+        Window *pWin = pExpr->pWin;
+        if( sqlite3WalkExprList(pWalker, pWin->pPartition) ) return WRC_Abort;
+        if( sqlite3WalkExprList(pWalker, pWin->pOrderBy) ) return WRC_Abort;
+        if( sqlite3WalkExpr(pWalker, pWin->pFilter) ) return WRC_Abort;
+      }
+#endif
     }
     break;
   }
@@ -93426,6 +94370,9 @@ static int lookupName(
           if( sqlite3StrICmp(zTabName, zTab)!=0 ){
             continue;
           }
+          if( IN_RENAME_OBJECT && pItem->zAlias ){
+            sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->pTab);
+          }
         }
         if( 0==(cntTab++) ){
           pMatch = pItem;
@@ -93511,9 +94458,15 @@ static int lookupName(
 #ifndef SQLITE_OMIT_UPSERT
           if( pExpr->iTable==2 ){
             testcase( iCol==(-1) );
-            pExpr->iTable = pNC->uNC.pUpsert->regData + iCol;
-            eNewExprOp = TK_REGISTER;
-            ExprSetProperty(pExpr, EP_Alias);
+            if( IN_RENAME_OBJECT ){
+              pExpr->iColumn = iCol;
+              pExpr->pTab = pTab;
+              eNewExprOp = TK_COLUMN;
+            }else{
+              pExpr->iTable = pNC->uNC.pUpsert->regData + iCol;
+              eNewExprOp = TK_REGISTER;
+              ExprSetProperty(pExpr, EP_Alias);
+            }
           }else
 #endif /* SQLITE_OMIT_UPSERT */
           {
@@ -93598,6 +94551,9 @@ static int lookupName(
           cnt = 1;
           pMatch = 0;
           assert( zTab==0 && zDb==0 );
+          if( IN_RENAME_OBJECT ){
+            sqlite3RenameTokenRemap(pParse, 0, (void*)pExpr);
+          }
           goto lookupname_end;
         }
       } 
@@ -93825,17 +94781,24 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
         zTable = 0;
         zColumn = pExpr->u.zToken;
       }else{
+        Expr *pLeft = pExpr->pLeft;
         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;
+          zDb = pLeft->u.zToken;
+          pLeft = pRight->pLeft;
+          pRight = pRight->pRight;
+        }
+        zTable = pLeft->u.zToken;
+        zColumn = pRight->u.zToken;
+        if( IN_RENAME_OBJECT ){
+          sqlite3RenameTokenRemap(pParse, (void*)pExpr, (void*)pRight);
+        }
+        if( IN_RENAME_OBJECT ){
+          sqlite3RenameTokenRemap(pParse, (void*)&pExpr->pTab, (void*)pLeft);
         }
       }
       return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr);
@@ -93918,40 +94881,95 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
                    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
+
+      if( 0==IN_RENAME_OBJECT ){
+#ifndef SQLITE_OMIT_WINDOWFUNC
+        assert( is_agg==0 || (pDef->funcFlags & SQLITE_FUNC_MINMAX)
+          || (pDef->xValue==0 && pDef->xInverse==0)
+          || (pDef->xValue && pDef->xInverse && pDef->xSFunc && pDef->xFinalize)
+        );
+        if( pDef && pDef->xValue==0 && pExpr->pWin ){
+          sqlite3ErrorMsg(pParse, 
+              "%.*s() may not be used as a window function", nId, zId
+          );
+          pNC->nErr++;
+        }else if( 
+              (is_agg && (pNC->ncFlags & NC_AllowAgg)==0)
+           || (is_agg && (pDef->funcFlags & SQLITE_FUNC_WINDOW) && !pExpr->pWin)
+           || (is_agg && pExpr->pWin && (pNC->ncFlags & NC_AllowWin)==0)
+        ){
+          const char *zType;
+          if( (pDef->funcFlags & SQLITE_FUNC_WINDOW) || pExpr->pWin ){
+            zType = "window";
+          }else{
+            zType = "aggregate";
+          }
+          sqlite3ErrorMsg(pParse, "misuse of %s function %.*s()",zType,nId,zId);
+          pNC->nErr++;
+          is_agg = 0;
+        }
+#else
+        if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) ){
+          sqlite3ErrorMsg(pParse,"misuse of aggregate function %.*s()",nId,zId);
+          pNC->nErr++;
+          is_agg = 0;
+        }
+#endif
+        else if( no_such_func && pParse->db->init.busy==0
 #ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
-                && pParse->explain==0
+                  && 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;
+        ){
+          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 ){
+#ifndef SQLITE_OMIT_WINDOWFUNC
+          pNC->ncFlags &= ~(pExpr->pWin ? NC_AllowWin : NC_AllowAgg);
+#else
+          pNC->ncFlags &= ~NC_AllowAgg;
+#endif
+        }
+      }
       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);
+#ifndef SQLITE_OMIT_WINDOWFUNC
+        if( pExpr->pWin ){
+          Select *pSel = pNC->pWinSelect;
+          sqlite3WalkExprList(pWalker, pExpr->pWin->pPartition);
+          sqlite3WalkExprList(pWalker, pExpr->pWin->pOrderBy);
+          sqlite3WalkExpr(pWalker, pExpr->pWin->pFilter);
+          sqlite3WindowUpdate(pParse, pSel->pWinDefn, pExpr->pWin, pDef);
+          if( 0==pSel->pWin 
+           || 0==sqlite3WindowCompare(pParse, pSel->pWin, pExpr->pWin) 
+          ){
+            pExpr->pWin->pNextWin = pSel->pWin;
+            pSel->pWin = pExpr->pWin;
+          }
+          pNC->ncFlags |= NC_AllowWin;
+        }else
+#endif /* SQLITE_OMIT_WINDOWFUNC */
+        {
+          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;
         }
-        pNC->ncFlags |= NC_AllowAgg;
       }
       /* FIX ME:  Compute pExpr->affinity based on the expected return
       ** type of the function 
@@ -94352,6 +95370,19 @@ static int resolveOrderGroupBy(
     }
     for(j=0; j<pSelect->pEList->nExpr; j++){
       if( sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){
+#ifndef SQLITE_OMIT_WINDOWFUNC
+        if( pE->pWin ){
+          /* Since this window function is being changed into a reference
+          ** to the same window function the result set, remove the instance
+          ** of this window function from the Select.pWin list. */
+          Window **pp;
+          for(pp=&pSelect->pWin; *pp; pp=&(*pp)->pNextWin){
+            if( *pp==pE->pWin ){
+              *pp = (*pp)->pNextWin;
+            }    
+          }
+        }
+#endif
         pItem->u.x.iOrderByCol = j+1;
       }
     }
@@ -94408,6 +95439,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
     */
     memset(&sNC, 0, sizeof(sNC));
     sNC.pParse = pParse;
+    sNC.pWinSelect = p;
     if( sqlite3ResolveExprNames(&sNC, p->pLimit) ){
       return WRC_Abort;
     }
@@ -94456,12 +95488,13 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
     /* Set up the local name-context to pass to sqlite3ResolveExprNames() to
     ** resolve the result-set expression list.
     */
-    sNC.ncFlags = NC_AllowAgg;
+    sNC.ncFlags = NC_AllowAgg|NC_AllowWin;
     sNC.pSrcList = p->pSrc;
     sNC.pNext = pOuterNC;
   
     /* Resolve names in the result set. */
     if( sqlite3ResolveExprListNames(&sNC, p->pEList) ) return WRC_Abort;
+    sNC.ncFlags &= ~NC_AllowWin;
   
     /* If there are no aggregate functions in the result-set, and no GROUP BY 
     ** expression, do not allow aggregates in any of the other expressions.
@@ -94510,7 +95543,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
     ** outer queries 
     */
     sNC.pNext = 0;
-    sNC.ncFlags |= NC_AllowAgg;
+    sNC.ncFlags |= NC_AllowAgg|NC_AllowWin;
 
     /* 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
@@ -94541,6 +95574,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
     if( db->mallocFailed ){
       return WRC_Abort;
     }
+    sNC.ncFlags &= ~NC_AllowWin;
   
     /* Resolve the GROUP BY clause.  At the same time, make sure 
     ** the GROUP BY clause does not contain aggregate functions.
@@ -94889,14 +95923,6 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *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
@@ -94910,6 +95936,14 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
       }
       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( p->flags & EP_Collate ){
       if( p->pLeft && (p->pLeft->flags & EP_Collate)!=0 ){
         p = p->pLeft;
@@ -95329,7 +96363,6 @@ static void codeVectorCompare(
     Expr *pL, *pR; 
     int r1, r2;
     assert( i>=0 && i<nLeft );
-    if( i>0 ) sqlite3ExprCachePush(pParse);
     r1 = exprVectorRegister(pParse, pLeft, i, regLeft, &pL, &regFree1);
     r2 = exprVectorRegister(pParse, pRight, i, regRight, &pR, &regFree2);
     codeCompare(pParse, pL, pR, opx, r1, r2, dest, p5);
@@ -95341,7 +96374,6 @@ static void codeVectorCompare(
     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;
     }
@@ -95689,7 +96721,12 @@ SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3 *db, Expr *pLeft, Expr *pRight){
 ** Construct a new expression node for a function with multiple
 ** arguments.
 */
-SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *pToken){
+SQLITE_PRIVATE Expr *sqlite3ExprFunction(
+  Parse *pParse,        /* Parsing context */
+  ExprList *pList,      /* Argument list */
+  Token *pToken,        /* Name of the function */
+  int eDistinct         /* SF_Distinct or SF_ALL or 0 */
+){
   Expr *pNew;
   sqlite3 *db = pParse->db;
   assert( pToken );
@@ -95698,10 +96735,14 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *
     sqlite3ExprListDelete(db, pList); /* Avoid memory leak when malloc fails */
     return 0;
   }
+  if( pList && pList->nExpr > pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
+    sqlite3ErrorMsg(pParse, "too many arguments on function %T", pToken);
+  }
   pNew->x.pList = pList;
   ExprSetProperty(pNew, EP_HasFunc);
   assert( !ExprHasProperty(pNew, EP_xIsSelect) );
   sqlite3ExprSetHeightAndFlags(pParse, pNew);
+  if( eDistinct==SF_Distinct ) ExprSetProperty(pNew, EP_Distinct);
   return pNew;
 }
 
@@ -95811,6 +96852,9 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
     }else{
       sqlite3ExprListDelete(db, p->x.pList);
     }
+    if( !ExprHasProperty(p, EP_Reduced) ){
+      sqlite3WindowDelete(db, p->pWin);
+    }
   }
   if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken);
   if( !ExprHasProperty(p, EP_Static) ){
@@ -95859,7 +96903,7 @@ static int exprStructSize(Expr *p){
 ** 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
+** later parts of the 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
@@ -95871,7 +96915,11 @@ static int dupedExprStructSize(Expr *p, int flags){
   assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */
   assert( EXPR_FULLSIZE<=0xfff );
   assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 );
-  if( 0==flags || p->op==TK_SELECT_COLUMN ){
+  if( 0==flags || p->op==TK_SELECT_COLUMN 
+#ifndef SQLITE_OMIT_WINDOWFUNC
+   || p->pWin 
+#endif
+  ){
     nSize = EXPR_FULLSIZE;
   }else{
     assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
@@ -96011,6 +97059,13 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
         *pzBuffer = zAlloc;
       }
     }else{
+#ifndef SQLITE_OMIT_WINDOWFUNC
+      if( ExprHasProperty(p, EP_Reduced|EP_TokenOnly) ){
+        pNew->pWin = 0;
+      }else{
+        pNew->pWin = sqlite3WindowDup(db, pNew, p->pWin);
+      }
+#endif /* SQLITE_OMIT_WINDOWFUNC */
       if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){
         if( pNew->op==TK_SELECT_COLUMN ){
           pNew->pLeft = p->pLeft;
@@ -96217,7 +97272,11 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){
     pNew->addrOpenEphm[1] = -1;
     pNew->nSelectRow = p->nSelectRow;
     pNew->pWith = withDup(db, p->pWith);
-    sqlite3SelectSetName(pNew, p->zSelName);
+#ifndef SQLITE_OMIT_WINDOWFUNC
+    pNew->pWin = 0;
+    pNew->pWinDefn = sqlite3WindowListDup(db, p->pWinDefn);
+#endif
+    pNew->selId = p->selId;
     *pp = pNew;
     pp = &pNew->pPrior;
     pNext = pNew;
@@ -96389,6 +97448,9 @@ SQLITE_PRIVATE void sqlite3ExprListSetName(
     assert( pItem->zName==0 );
     pItem->zName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n);
     if( dequote ) sqlite3Dequote(pItem->zName);
+    if( IN_RENAME_OBJECT ){
+      sqlite3RenameTokenMap(pParse, (void*)pItem->zName, pName);
+    }
   }
 }
 
@@ -96569,6 +97631,9 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
       testcase( pExpr->op==TK_COLUMN );
       testcase( pExpr->op==TK_AGG_FUNCTION );
       testcase( pExpr->op==TK_AGG_COLUMN );
+      if( ExprHasProperty(pExpr, EP_FixedCol) && pWalker->eCode!=2 ){
+        return WRC_Continue;
+      }
       if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){
         return WRC_Continue;
       }
@@ -96624,10 +97689,17 @@ SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr *p){
 }
 
 /*
-** 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.
+** Walk an expression tree.  Return non-zero if
+**
+**   (1) the expression is constant, and
+**   (2) the expression does originate in the ON or USING clause
+**       of a LEFT JOIN, and
+**   (3) the expression does not contain any EP_FixedCol TK_COLUMN
+**       operands created by the constant propagation optimization.
+**
+** When this routine returns true, it indicates that the expression
+** can be added to the pParse->pConstExpr list and evaluated once when
+** the prepared statement starts up.  See sqlite3ExprCodeAtInit().
 */
 SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr *p){
   return exprIsConst(p, 2, 0);
@@ -96657,7 +97729,7 @@ static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){
     Expr *p = pGroupBy->a[i].pExpr;
     if( sqlite3ExprCompare(0, pExpr, p, -1)<2 ){
       CollSeq *pColl = sqlite3ExprNNCollSeq(pWalker->pParse, p);
-      if( sqlite3_stricmp("BINARY", pColl->zName)==0 ){
+      if( sqlite3IsBinary(pColl) ){
         return WRC_Prune;
       }
     }
@@ -97079,7 +98151,8 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
 
       sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
       eType = IN_INDEX_ROWID;
-
+      ExplainQueryPlan((pParse, 0,
+            "USING ROWID SEARCH ON TABLE %s FOR IN-OPERATOR",pTab->zName));
       sqlite3VdbeJumpHere(v, iAddr);
     }else{
       Index *pIdx;                         /* Iterator variable */
@@ -97338,7 +98411,6 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
   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:
@@ -97474,7 +98546,6 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
               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);
             }
           }
@@ -97555,7 +98626,6 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
   if( jmpIfDynamic>=0 ){
     sqlite3VdbeJumpHere(v, jmpIfDynamic);
   }
-  sqlite3ExprCachePop(pParse);
 
   return rReg;
 }
@@ -97674,7 +98744,6 @@ static void sqlite3ExprCodeIN(
   ** 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; i<nVector && aiMap[i]==i; i++){} /* Are LHS fields reordered? */
   if( i==nVector ){
@@ -97833,7 +98902,6 @@ static void sqlite3ExprCodeIN(
 
 sqlite3ExprCodeIN_finished:
   if( rLhs!=rLhsOrig ) sqlite3ReleaseTempReg(pParse, rLhs);
-  sqlite3ExprCachePop(pParse);
   VdbeComment((v, "end IN expr"));
 sqlite3ExprCodeIN_oom_error:
   sqlite3DbFree(pParse->db, aiMap);
@@ -97901,145 +98969,6 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
   }
 }
 
-/*
-** Erase column-cache entry number i
-*/
-static void cacheEntryClear(Parse *pParse, int i){
-  if( pParse->aColCache[i].tempReg ){
-    if( pParse->nTempReg<ArraySize(pParse->aTempReg) ){
-      pParse->aTempReg[pParse->nTempReg++] = pParse->aColCache[i].iReg;
-    }
-  }
-  pParse->nColCache--;
-  if( i<pParse->nColCache ){
-    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; i<pParse->nColCache; 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; i<SQLITE_N_COLCACHE; i++, p++){
-      if( p->lru<minLru ){
-        idxLru = i;
-        minLru = p->lru;
-      }
-    }
-    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( i<pParse->nColCache ){
-    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( i<pParse->nColCache ){
-    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; i<pParse->nColCache; 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.
@@ -98095,12 +99024,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(
 
 /*
 ** 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().
+** table pTab and store the column value in register iReg. 
 **
 ** There must be an open cursor to pTab in iTable when this routine
 ** is called.  If iColumn<0 then code is generated that extracts the rowid.
@@ -98114,96 +99038,23 @@ SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(
   u8 p5            /* P5 value for OP_Column + FLAGS */
 ){
   Vdbe *v = pParse->pVdbe;
-  int i;
-  struct yColCache *p;
-
-  for(i=0, p=pParse->aColCache; i<pParse->nColCache; 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; i<pParse->nColCache; i++){
-    if( pParse->aColCache[i].tempReg
-     && pParse->nTempReg<ArraySize(pParse->aTempReg)
-    ){
-       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.
+** over to iTo..iTo+nReg-1.
 */
 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; i<pParse->nColCache; 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
@@ -98301,6 +99152,28 @@ expr_code_doover:
     }
     case TK_COLUMN: {
       int iTab = pExpr->iTable;
+      if( ExprHasProperty(pExpr, EP_FixedCol) ){
+        /* This COLUMN expression is really a constant due to WHERE clause
+        ** constraints, and that constant is coded by the pExpr->pLeft
+        ** expresssion.  However, make sure the constant has the correct
+        ** datatype by applying the Affinity of the table column to the
+        ** constant.
+        */
+        int iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target);
+        int aff = sqlite3TableColumnAffinity(pExpr->pTab, pExpr->iColumn);
+        if( aff!=SQLITE_AFF_BLOB ){
+          static const char zAff[] = "B\000C\000D\000E";
+          assert( SQLITE_AFF_BLOB=='A' );
+          assert( SQLITE_AFF_TEXT=='B' );
+          if( iReg!=target ){
+            sqlite3VdbeAddOp2(v, OP_SCopy, iReg, target);
+            iReg = target;
+          }
+          sqlite3VdbeAddOp4(v, OP_Affinity, iReg, 1, 0,
+                            &zAff[(aff-'B')*2], P4_STATIC);
+        }
+        return iReg;
+      }
       if( iTab<0 ){
         if( pParse->iSelfTab<0 ){
           /* Generating CHECK constraints or inserting into partial index */
@@ -98381,8 +99254,6 @@ expr_code_doover:
       }
       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 */
@@ -98526,6 +99397,12 @@ expr_code_doover:
       u8 enc = ENC(db);      /* The text encoding used by this database */
       CollSeq *pColl = 0;    /* A collating sequence */
 
+#ifndef SQLITE_OMIT_WINDOWFUNC
+      if( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) && pExpr->pWin ){
+        return pExpr->pWin->regResult;
+      }
+#endif
+
       if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){
         /* SQL functions can be expensive. So try to move constant functions
         ** out of the inner loop, even if that means an extra OP_Copy. */
@@ -98562,10 +99439,7 @@ expr_code_doover:
         for(i=1; i<nFarg; i++){
           sqlite3VdbeAddOp2(v, OP_NotNull, target, endCoalesce);
           VdbeCoverage(v);
-          sqlite3ExprCacheRemove(pParse, target, 1);
-          sqlite3ExprCachePush(pParse);
           sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target);
-          sqlite3ExprCachePop(pParse);
         }
         sqlite3VdbeResolveLabel(v, endCoalesce);
         break;
@@ -98631,10 +99505,8 @@ expr_code_doover:
           }
         }
 
-        sqlite3ExprCachePush(pParse);     /* Ticket 2ea2425d34be */
         sqlite3ExprCodeExprList(pParse, pFarg, r1, 0,
                                 SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR);
-        sqlite3ExprCachePop(pParse);      /* Ticket 2ea2425d34be */
       }else{
         r1 = 0;
       }
@@ -98651,7 +99523,7 @@ expr_code_doover:
       ** "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) ){
+      if( nFarg>=2 && ExprHasProperty(pExpr, EP_InfixFunc) ){
         pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[1].pExpr);
       }else if( nFarg>0 ){
         pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[0].pExpr);
@@ -98807,9 +99679,7 @@ expr_code_doover:
     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;
@@ -98846,7 +99716,6 @@ expr_code_doover:
       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);
@@ -98870,7 +99739,6 @@ expr_code_doover:
         regFree1 = 0;
       }
       for(i=0; i<nExpr-1; i=i+2){
-        sqlite3ExprCachePush(pParse);
         if( pX ){
           assert( pTest!=0 );
           opCompare.pRight = aListelem[i].pExpr;
@@ -98883,18 +99751,13 @@ expr_code_doover:
         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;
     }
@@ -99044,7 +99907,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse *pParse, Expr *pExpr, int target){
 ** might choose to code the expression at initialization time.
 */
 SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){
-  if( pParse->okConstFactor && sqlite3ExprIsConstant(pExpr) ){
+  if( pParse->okConstFactor && sqlite3ExprIsConstantNotJoin(pExpr) ){
     sqlite3ExprCodeAtInit(pParse, pExpr, target);
   }else{
     sqlite3ExprCode(pParse, pExpr, target);
@@ -99126,7 +99989,9 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(
       }else{
         sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i);
       }
-    }else if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){
+    }else if( (flags & SQLITE_ECEL_FACTOR)!=0
+           && sqlite3ExprIsConstantNotJoin(pExpr)
+    ){
       sqlite3ExprCodeAtInit(pParse, pExpr, target+i);
     }else{
       int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
@@ -99252,18 +100117,14 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
       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: {
@@ -99422,19 +100283,15 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
     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: {
@@ -99656,7 +100513,8 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTa
   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(pParse, pA->pLeft, pB->pLeft, iTab) ) return 2;
+    if( (combinedFlags & EP_FixedCol)==0
+     && sqlite3ExprCompare(pParse, pA->pLeft, pB->pLeft, iTab) ) return 2;
     if( sqlite3ExprCompare(pParse, pA->pRight, pB->pRight, iTab) ) return 2;
     if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2;
     assert( (combinedFlags & EP_Reduced)==0 );
@@ -99665,6 +100523,21 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTa
       if( pA->iTable!=pB->iTable 
        && (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2;
     }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+    /* Justification for the assert():
+    ** window functions have p->op==TK_FUNCTION but aggregate functions
+    ** have p->op==TK_AGG_FUNCTION.  So any comparison between an aggregate
+    ** function and a window function should have failed before reaching
+    ** this point.  And, it is not possible to have a window function and
+    ** a scalar function with the same name and number of arguments.  So
+    ** if we reach this point, either A and B both window functions or
+    ** neither are a window functions. */
+    assert( (pA->pWin==0)==(pB->pWin==0) );
+
+    if( pA->pWin!=0 ){
+      if( sqlite3WindowCompare(pParse,pA->pWin,pB->pWin)!=0 ) return 2;
+    }
+#endif
   }
   return 0;
 }
@@ -100186,21 +101059,9 @@ SQLITE_PRIVATE int sqlite3GetTempReg(Parse *pParse){
 /*
 ** 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->nTempReg<ArraySize(pParse->aTempReg) ){
-    int i;
-    struct yColCache *p;
-    for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
-      if( p->iReg==iReg ){
-        p->tempReg = 1;
-        return;
-      }
-    }
     pParse->aTempReg[pParse->nTempReg++] = iReg;
   }
 }
@@ -100214,7 +101075,6 @@ SQLITE_PRIVATE int sqlite3GetTempRange(Parse *pParse, int nReg){
   i = pParse->iRangeReg;
   n = pParse->nRangeReg;
   if( nReg<=n ){
-    assert( !usedAsColumnCache(pParse, i, i+n-1) );
     pParse->iRangeReg += nReg;
     pParse->nRangeReg -= nReg;
   }else{
@@ -100228,7 +101088,6 @@ SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){
     sqlite3ReleaseTempReg(pParse, iReg);
     return;
   }
-  sqlite3ExprCacheRemove(pParse, iReg, nReg);
   if( nReg>pParse->nRangeReg ){
     pParse->nRangeReg = nReg;
     pParse->iRangeReg = iReg;
@@ -100290,366 +101149,63 @@ SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){
 */
 #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=<constant1> OR name=<constant2> OR ...
-**
-** If argument zWhere is NULL, then a pointer string containing the text 
-** "name=<constant>" is returned, where <constant> 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.
+** 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.
 **
-** If argument zWhere is not NULL, then the string returned is 
-** "<where> OR name=<constant>", where <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.
+** Or, if zName is not a system table, zero 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;
+static int isSystemTable(Parse *pParse, const char *zName){
+  if( 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){
+    sqlite3ErrorMsg(pParse, "table %s may not be altered", zName);
+    return 1;
   }
-  return zWhere;
+  return 0;
 }
 
 /*
-** 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.
+** Generate code to verify that the schemas of database zDb and, if
+** bTemp is not true, database "temp", can still be parsed. This is
+** called at the end of the generation of an ALTER TABLE ... RENAME ...
+** statement to ensure that the operation has not rendered any schema
+** objects unusable.
 */
-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);
+static void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){
+  sqlite3NestedParse(pParse, 
+      "SELECT 1 "
+      "FROM \"%w\".%s "
+      "WHERE name NOT LIKE 'sqlite_%%'"
+      " AND sql NOT LIKE 'create virtual%%'"
+      " AND sqlite_rename_test(%Q, sql, type, name, %d)=NULL ",
+      zDb, MASTER_NAME, 
+      zDb, bTemp
+  );
 
-#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);
+  if( bTemp==0 ){
+    sqlite3NestedParse(pParse, 
+        "SELECT 1 "
+        "FROM temp.%s "
+        "WHERE name NOT LIKE 'sqlite_%%'"
+        " AND sql NOT LIKE 'create virtual%%'"
+        " AND sqlite_rename_test(%Q, sql, type, name, 1)=NULL ",
+        MASTER_NAME, zDb 
+    );
   }
-#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.
+** Generate code to reload the schema for database iDb. And, if iDb!=1, for
+** the temp database as well.
 */
-static int isSystemTable(Parse *pParse, const char *zName){
-  if( 0==sqlite3StrNICmp(zName, "sqlite_", 7) ){
-    sqlite3ErrorMsg(pParse, "table %s may not be altered", zName);
-    return 1;
+static void renameReloadSchema(Parse *pParse, int iDb){
+  Vdbe *v = pParse->pVdbe;
+  if( v ){
+    sqlite3ChangeCookie(pParse, iDb);
+    sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0);
+    if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0);
   }
-  return 0;
 }
 
 /*
@@ -100669,9 +101225,6 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
   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() */
   u32 savedDbFlags;         /* Saved value of db->mDbFlags */
 
@@ -100744,8 +101297,6 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
   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
@@ -100765,31 +101316,20 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
   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
+  /* Rewrite all CREATE TABLE, INDEX, TRIGGER or VIEW statements in
+  ** the schema to use the new table name.  */
+  sqlite3NestedParse(pParse, 
+      "UPDATE \"%w\".%s SET "
+      "sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, %d) "
+      "WHERE (type!='index' OR tbl_name=%Q COLLATE nocase)"
+      "AND   name NOT LIKE 'sqlite_%%'"
+      , zDb, MASTER_NAME, zDb, zTabName, zName, (iDb==1), zTabName
+  );
 
-  /* Modify the sqlite_master table to use the new table name. */
+  /* Update the tbl_name and name columns of the sqlite_master table
+  ** as required.  */
   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 "
@@ -100798,11 +101338,9 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
             "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
+      zDb, MASTER_NAME, 
+      zName, zName, zName, 
+      nTabName, zTabName
   );
 
 #ifndef SQLITE_OMIT_AUTOINCREMENT
@@ -100816,35 +101354,23 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
   }
 #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 ){
+  /* If the table being renamed is not itself part of the temp database,
+  ** edit view and trigger definitions within the temp database 
+  ** as required.  */
+  if( iDb!=1 ){
     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);
-      }
-    }
+            "sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, 1), "
+            "tbl_name = "
+              "CASE WHEN tbl_name=%Q COLLATE nocase AND "
+              "          sqlite_rename_test(%Q, sql, type, name, 1) "
+              "THEN %Q ELSE tbl_name END "
+            "WHERE type IN ('view', 'trigger')"
+        , zDb, zTabName, zName, zTabName, zDb, zName);
   }
-#endif
 
-  /* Drop and reload the internal table schema. */
-  reloadTableSchema(pParse, pTab, zName);
+  renameReloadSchema(pParse, iDb);
+  renameTestSchema(pParse, zDb, iDb==1);
 
 exit_rename_table:
   sqlite3SrcListDelete(db, pSrc);
@@ -100870,12 +101396,11 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
   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 */
+  Vdbe *v;                  /* 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 );
 
@@ -100970,17 +101495,20 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
   ** 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);
+  v = sqlite3GetVdbe(pParse);
+  if( v ){
+    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);
+  /* Reload the table definition */
+  renameReloadSchema(pParse, iDb);
 }
 
 /*
@@ -101001,7 +101529,6 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
 SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
   Table *pNew;
   Table *pTab;
-  Vdbe *v;
   int iDb;
   int i;
   int nAlloc;
@@ -101065,16 +101592,1130 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
   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;
 }
+
+/*
+** Parameter pTab is the subject of an ALTER TABLE ... RENAME COLUMN
+** command. This function checks if the table is a view or virtual
+** table (columns of views or virtual tables may not be renamed). If so,
+** it loads an error message into pParse and returns non-zero.
+**
+** Or, if pTab is not a view or virtual table, zero is returned.
+*/
+#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
+static int isRealTable(Parse *pParse, Table *pTab){
+  const char *zType = 0;
+#ifndef SQLITE_OMIT_VIEW
+  if( pTab->pSelect ){
+    zType = "view";
+  }
+#endif
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+  if( IsVirtual(pTab) ){
+    zType = "virtual table";
+  }
+#endif
+  if( zType ){
+    sqlite3ErrorMsg(
+        pParse, "cannot rename columns of %s \"%s\"", zType, pTab->zName
+    );
+    return 1;
+  }
+  return 0;
+}
+#else /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */
+# define isRealTable(x,y) (0)
+#endif
+
+/*
+** Handles the following parser reduction:
+**
+**  cmd ::= ALTER TABLE pSrc RENAME COLUMN pOld TO pNew
+*/
+SQLITE_PRIVATE void sqlite3AlterRenameColumn(
+  Parse *pParse,                  /* Parsing context */
+  SrcList *pSrc,                  /* Table being altered.  pSrc->nSrc==1 */
+  Token *pOld,                    /* Name of column being changed */
+  Token *pNew                     /* New column name */
+){
+  sqlite3 *db = pParse->db;       /* Database connection */
+  Table *pTab;                    /* Table being updated */
+  int iCol;                       /* Index of column being renamed */
+  char *zOld = 0;                 /* Old column name */
+  char *zNew = 0;                 /* New column name */
+  const char *zDb;                /* Name of schema containing the table */
+  int iSchema;                    /* Index of the schema */
+  int bQuote;                     /* True to quote the new name */
+
+  /* Locate the table to be altered */
+  pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
+  if( !pTab ) goto exit_rename_column;
+
+  /* Cannot alter a system table */
+  if( SQLITE_OK!=isSystemTable(pParse, pTab->zName) ) goto exit_rename_column;
+  if( SQLITE_OK!=isRealTable(pParse, pTab) ) goto exit_rename_column;
+
+  /* Which schema holds the table to be altered */  
+  iSchema = sqlite3SchemaToIndex(db, pTab->pSchema);
+  assert( iSchema>=0 );
+  zDb = db->aDb[iSchema].zDbSName;
+
+#ifndef SQLITE_OMIT_AUTHORIZATION
+  /* Invoke the authorization callback. */
+  if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, 0) ){
+    goto exit_rename_column;
+  }
+#endif
+
+  /* Make sure the old name really is a column name in the table to be
+  ** altered.  Set iCol to be the index of the column being renamed */
+  zOld = sqlite3NameFromToken(db, pOld);
+  if( !zOld ) goto exit_rename_column;
+  for(iCol=0; iCol<pTab->nCol; iCol++){
+    if( 0==sqlite3StrICmp(pTab->aCol[iCol].zName, zOld) ) break;
+  }
+  if( iCol==pTab->nCol ){
+    sqlite3ErrorMsg(pParse, "no such column: \"%s\"", zOld);
+    goto exit_rename_column;
+  }
+
+  /* Do the rename operation using a recursive UPDATE statement that
+  ** uses the sqlite_rename_column() SQL function to compute the new
+  ** CREATE statement text for the sqlite_master table.
+  */
+  zNew = sqlite3NameFromToken(db, pNew);
+  if( !zNew ) goto exit_rename_column;
+  assert( pNew->n>0 );
+  bQuote = sqlite3Isquote(pNew->z[0]);
+  sqlite3NestedParse(pParse, 
+      "UPDATE \"%w\".%s SET "
+      "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, %d) "
+      "WHERE name NOT LIKE 'sqlite_%%' AND (type != 'index' OR tbl_name = %Q)"
+      " AND sql NOT LIKE 'create virtual%%'",
+      zDb, MASTER_NAME, 
+      zDb, pTab->zName, iCol, zNew, bQuote, iSchema==1,
+      pTab->zName
+  );
+
+  sqlite3NestedParse(pParse, 
+      "UPDATE temp.%s SET "
+      "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, 1) "
+      "WHERE type IN ('trigger', 'view')",
+      MASTER_NAME, 
+      zDb, pTab->zName, iCol, zNew, bQuote
+  );
+
+  /* Drop and reload the database schema. */
+  renameReloadSchema(pParse, iSchema);
+  renameTestSchema(pParse, zDb, iSchema==1);
+
+ exit_rename_column:
+  sqlite3SrcListDelete(db, pSrc);
+  sqlite3DbFree(db, zOld);
+  sqlite3DbFree(db, zNew);
+  return;
+}
+
+/*
+** Each RenameToken object maps an element of the parse tree into
+** the token that generated that element.  The parse tree element
+** might be one of:
+**
+**     *  A pointer to an Expr that represents an ID
+**     *  The name of a table column in Column.zName
+**
+** A list of RenameToken objects can be constructed during parsing.
+** Each new object is created by sqlite3RenameTokenMap().
+** As the parse tree is transformed, the sqlite3RenameTokenRemap()
+** routine is used to keep the mapping current.
+**
+** After the parse finishes, renameTokenFind() routine can be used
+** to look up the actual token value that created some element in
+** the parse tree.
+*/
+struct RenameToken {
+  void *p;               /* Parse tree element created by token t */
+  Token t;               /* The token that created parse tree element p */
+  RenameToken *pNext;    /* Next is a list of all RenameToken objects */
+};
+
+/*
+** The context of an ALTER TABLE RENAME COLUMN operation that gets passed
+** down into the Walker.
+*/
+typedef struct RenameCtx RenameCtx;
+struct RenameCtx {
+  RenameToken *pList;             /* List of tokens to overwrite */
+  int nList;                      /* Number of tokens in pList */
+  int iCol;                       /* Index of column being renamed */
+  Table *pTab;                    /* Table being ALTERed */ 
+  const char *zOld;               /* Old column name */
+};
+
+#ifdef SQLITE_DEBUG
+/*
+** This function is only for debugging. It performs two tasks:
+**
+**   1. Checks that pointer pPtr does not already appear in the 
+**      rename-token list.
+**
+**   2. Dereferences each pointer in the rename-token list.
+**
+** The second is most effective when debugging under valgrind or
+** address-sanitizer or similar. If any of these pointers no longer 
+** point to valid objects, an exception is raised by the memory-checking 
+** tool.
+**
+** The point of this is to prevent comparisons of invalid pointer values.
+** Even though this always seems to work, it is undefined according to the
+** C standard. Example of undefined comparison:
+**
+**     sqlite3_free(x);
+**     if( x==y ) ...
+**
+** Technically, as x no longer points into a valid object or to the byte
+** following a valid object, it may not be used in comparison operations.
+*/
+static void renameTokenCheckAll(Parse *pParse, void *pPtr){
+  if( pParse->nErr==0 && pParse->db->mallocFailed==0 ){
+    RenameToken *p;
+    u8 i = 0;
+    for(p=pParse->pRename; p; p=p->pNext){
+      if( p->p ){
+        assert( p->p!=pPtr );
+        i += *(u8*)(p->p);
+      }
+    }
+  }
+}
+#else
+# define renameTokenCheckAll(x,y)
+#endif
+
+/*
+** Add a new RenameToken object mapping parse tree element pPtr into
+** token *pToken to the Parse object currently under construction.
+**
+** Return a copy of pPtr.
+*/
+SQLITE_PRIVATE void *sqlite3RenameTokenMap(Parse *pParse, void *pPtr, Token *pToken){
+  RenameToken *pNew;
+  assert( pPtr || pParse->db->mallocFailed );
+  renameTokenCheckAll(pParse, pPtr);
+  pNew = sqlite3DbMallocZero(pParse->db, sizeof(RenameToken));
+  if( pNew ){
+    pNew->p = pPtr;
+    pNew->t = *pToken;
+    pNew->pNext = pParse->pRename;
+    pParse->pRename = pNew;
+  }
+
+  return pPtr;
+}
+
+/*
+** It is assumed that there is already a RenameToken object associated
+** with parse tree element pFrom. This function remaps the associated token
+** to parse tree element pTo.
+*/
+SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse *pParse, void *pTo, void *pFrom){
+  RenameToken *p;
+  renameTokenCheckAll(pParse, pTo);
+  for(p=pParse->pRename; p; p=p->pNext){
+    if( p->p==pFrom ){
+      p->p = pTo;
+      break;
+    }
+  }
+}
+
+/*
+** Walker callback used by sqlite3RenameExprUnmap().
+*/
+static int renameUnmapExprCb(Walker *pWalker, Expr *pExpr){
+  Parse *pParse = pWalker->pParse;
+  sqlite3RenameTokenRemap(pParse, 0, (void*)pExpr);
+  return WRC_Continue;
+}
+
+/*
+** Remove all nodes that are part of expression pExpr from the rename list.
+*/
+SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse *pParse, Expr *pExpr){
+  Walker sWalker;
+  memset(&sWalker, 0, sizeof(Walker));
+  sWalker.pParse = pParse;
+  sWalker.xExprCallback = renameUnmapExprCb;
+  sqlite3WalkExpr(&sWalker, pExpr);
+}
+
+/*
+** Remove all nodes that are part of expression-list pEList from the 
+** rename list.
+*/
+SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse *pParse, ExprList *pEList){
+  if( pEList ){
+    int i;
+    Walker sWalker;
+    memset(&sWalker, 0, sizeof(Walker));
+    sWalker.pParse = pParse;
+    sWalker.xExprCallback = renameUnmapExprCb;
+    sqlite3WalkExprList(&sWalker, pEList);
+    for(i=0; i<pEList->nExpr; i++){
+      sqlite3RenameTokenRemap(pParse, 0, (void*)pEList->a[i].zName);
+    }
+  }
+}
+
+/*
+** Free the list of RenameToken objects given in the second argument
+*/
+static void renameTokenFree(sqlite3 *db, RenameToken *pToken){
+  RenameToken *pNext;
+  RenameToken *p;
+  for(p=pToken; p; p=pNext){
+    pNext = p->pNext;
+    sqlite3DbFree(db, p);
+  }
+}
+
+/*
+** Search the Parse object passed as the first argument for a RenameToken
+** object associated with parse tree element pPtr. If found, remove it
+** from the Parse object and add it to the list maintained by the
+** RenameCtx object passed as the second argument.
+*/
+static void renameTokenFind(Parse *pParse, struct RenameCtx *pCtx, void *pPtr){
+  RenameToken **pp;
+  assert( pPtr!=0 );
+  for(pp=&pParse->pRename; (*pp); pp=&(*pp)->pNext){
+    if( (*pp)->p==pPtr ){
+      RenameToken *pToken = *pp;
+      *pp = pToken->pNext;
+      pToken->pNext = pCtx->pList;
+      pCtx->pList = pToken;
+      pCtx->nList++;
+      break;
+    }
+  }
+}
+
+/*
+** This is a Walker select callback. It does nothing. It is only required
+** because without a dummy callback, sqlite3WalkExpr() and similar do not
+** descend into sub-select statements.
+*/
+static int renameColumnSelectCb(Walker *pWalker, Select *p){
+  UNUSED_PARAMETER(pWalker);
+  UNUSED_PARAMETER(p);
+  return WRC_Continue;
+}
+
+/*
+** This is a Walker expression callback.
+**
+** For every TK_COLUMN node in the expression tree, search to see
+** if the column being references is the column being renamed by an
+** ALTER TABLE statement.  If it is, then attach its associated
+** RenameToken object to the list of RenameToken objects being
+** constructed in RenameCtx object at pWalker->u.pRename.
+*/
+static int renameColumnExprCb(Walker *pWalker, Expr *pExpr){
+  RenameCtx *p = pWalker->u.pRename;
+  if( pExpr->op==TK_TRIGGER 
+   && pExpr->iColumn==p->iCol 
+   && pWalker->pParse->pTriggerTab==p->pTab
+  ){
+    renameTokenFind(pWalker->pParse, p, (void*)pExpr);
+  }else if( pExpr->op==TK_COLUMN 
+   && pExpr->iColumn==p->iCol 
+   && p->pTab==pExpr->pTab
+  ){
+    renameTokenFind(pWalker->pParse, p, (void*)pExpr);
+  }
+  return WRC_Continue;
+}
+
+/*
+** The RenameCtx contains a list of tokens that reference a column that
+** is being renamed by an ALTER TABLE statement.  Return the "last"
+** RenameToken in the RenameCtx and remove that RenameToken from the
+** RenameContext.  "Last" means the last RenameToken encountered when
+** the input SQL is parsed from left to right.  Repeated calls to this routine
+** return all column name tokens in the order that they are encountered
+** in the SQL statement.
+*/
+static RenameToken *renameColumnTokenNext(RenameCtx *pCtx){
+  RenameToken *pBest = pCtx->pList;
+  RenameToken *pToken;
+  RenameToken **pp;
+
+  for(pToken=pBest->pNext; pToken; pToken=pToken->pNext){
+    if( pToken->t.z>pBest->t.z ) pBest = pToken;
+  }
+  for(pp=&pCtx->pList; *pp!=pBest; pp=&(*pp)->pNext);
+  *pp = pBest->pNext;
+
+  return pBest;
+}
+
+/*
+** An error occured while parsing or otherwise processing a database
+** object (either pParse->pNewTable, pNewIndex or pNewTrigger) as part of an
+** ALTER TABLE RENAME COLUMN program. The error message emitted by the
+** sub-routine is currently stored in pParse->zErrMsg. This function
+** adds context to the error message and then stores it in pCtx.
+*/
+static void renameColumnParseError(
+  sqlite3_context *pCtx, 
+  int bPost,
+  sqlite3_value *pType,
+  sqlite3_value *pObject,
+  Parse *pParse
+){
+  const char *zT = (const char*)sqlite3_value_text(pType);
+  const char *zN = (const char*)sqlite3_value_text(pObject);
+  char *zErr;
+
+  zErr = sqlite3_mprintf("error in %s %s%s: %s", 
+      zT, zN, (bPost ? " after rename" : ""),
+      pParse->zErrMsg
+  );
+  sqlite3_result_error(pCtx, zErr, -1);
+  sqlite3_free(zErr);
+}
+
+/*
+** For each name in the the expression-list pEList (i.e. each
+** pEList->a[i].zName) that matches the string in zOld, extract the 
+** corresponding rename-token from Parse object pParse and add it
+** to the RenameCtx pCtx.
+*/
+static void renameColumnElistNames(
+  Parse *pParse, 
+  RenameCtx *pCtx, 
+  ExprList *pEList, 
+  const char *zOld
+){
+  if( pEList ){
+    int i;
+    for(i=0; i<pEList->nExpr; i++){
+      char *zName = pEList->a[i].zName;
+      if( 0==sqlite3_stricmp(zName, zOld) ){
+        renameTokenFind(pParse, pCtx, (void*)zName);
+      }
+    }
+  }
+}
+
+/*
+** For each name in the the id-list pIdList (i.e. each pIdList->a[i].zName) 
+** that matches the string in zOld, extract the corresponding rename-token 
+** from Parse object pParse and add it to the RenameCtx pCtx.
+*/
+static void renameColumnIdlistNames(
+  Parse *pParse, 
+  RenameCtx *pCtx, 
+  IdList *pIdList, 
+  const char *zOld
+){
+  if( pIdList ){
+    int i;
+    for(i=0; i<pIdList->nId; i++){
+      char *zName = pIdList->a[i].zName;
+      if( 0==sqlite3_stricmp(zName, zOld) ){
+        renameTokenFind(pParse, pCtx, (void*)zName);
+      }
+    }
+  }
+}
+
+/*
+** Parse the SQL statement zSql using Parse object (*p). The Parse object
+** is initialized by this function before it is used.
+*/
+static int renameParseSql(
+  Parse *p,                       /* Memory to use for Parse object */
+  const char *zDb,                /* Name of schema SQL belongs to */
+  int bTable,                     /* 1 -> RENAME TABLE, 0 -> RENAME COLUMN */
+  sqlite3 *db,                    /* Database handle */
+  const char *zSql,               /* SQL to parse */
+  int bTemp                       /* True if SQL is from temp schema */
+){
+  int rc;
+  char *zErr = 0;
+
+  db->init.iDb = bTemp ? 1 : sqlite3FindDbName(db, zDb);
+
+  /* Parse the SQL statement passed as the first argument. If no error
+  ** occurs and the parse does not result in a new table, index or
+  ** trigger object, the database must be corrupt. */
+  memset(p, 0, sizeof(Parse));
+  p->eParseMode = (bTable ? PARSE_MODE_RENAME_TABLE : PARSE_MODE_RENAME_COLUMN);
+  p->db = db;
+  p->nQueryLoop = 1;
+  rc = sqlite3RunParser(p, zSql, &zErr);
+  assert( p->zErrMsg==0 );
+  assert( rc!=SQLITE_OK || zErr==0 );
+  assert( (0!=p->pNewTable) + (0!=p->pNewIndex) + (0!=p->pNewTrigger)<2 );
+  p->zErrMsg = zErr;
+  if( db->mallocFailed ) rc = SQLITE_NOMEM;
+  if( rc==SQLITE_OK 
+   && p->pNewTable==0 && p->pNewIndex==0 && p->pNewTrigger==0 
+  ){
+    rc = SQLITE_CORRUPT_BKPT;
+  }
+
+#ifdef SQLITE_DEBUG
+  /* Ensure that all mappings in the Parse.pRename list really do map to
+  ** a part of the input string.  */
+  if( rc==SQLITE_OK ){
+    int nSql = sqlite3Strlen30(zSql);
+    RenameToken *pToken;
+    for(pToken=p->pRename; pToken; pToken=pToken->pNext){
+      assert( pToken->t.z>=zSql && &pToken->t.z[pToken->t.n]<=&zSql[nSql] );
+    }
+  }
+#endif
+
+  db->init.iDb = 0;
+  return rc;
+}
+
+/*
+** This function edits SQL statement zSql, replacing each token identified
+** by the linked list pRename with the text of zNew. If argument bQuote is
+** true, then zNew is always quoted first. If no error occurs, the result
+** is loaded into context object pCtx as the result.
+**
+** Or, if an error occurs (i.e. an OOM condition), an error is left in
+** pCtx and an SQLite error code returned.
+*/
+static int renameEditSql(
+  sqlite3_context *pCtx,          /* Return result here */
+  RenameCtx *pRename,             /* Rename context */
+  const char *zSql,               /* SQL statement to edit */
+  const char *zNew,               /* New token text */
+  int bQuote                      /* True to always quote token */
+){
+  int nNew = sqlite3Strlen30(zNew);
+  int nSql = sqlite3Strlen30(zSql);
+  sqlite3 *db = sqlite3_context_db_handle(pCtx);
+  int rc = SQLITE_OK;
+  char *zQuot;
+  char *zOut;
+  int nQuot;
+
+  /* Set zQuot to point to a buffer containing a quoted copy of the 
+  ** identifier zNew. If the corresponding identifier in the original 
+  ** ALTER TABLE statement was quoted (bQuote==1), then set zNew to
+  ** point to zQuot so that all substitutions are made using the
+  ** quoted version of the new column name.  */
+  zQuot = sqlite3MPrintf(db, "\"%w\"", zNew);
+  if( zQuot==0 ){
+    return SQLITE_NOMEM;
+  }else{
+    nQuot = sqlite3Strlen30(zQuot);
+  }
+  if( bQuote ){
+    zNew = zQuot;
+    nNew = nQuot;
+  }
+
+  /* At this point pRename->pList contains a list of RenameToken objects
+  ** corresponding to all tokens in the input SQL that must be replaced
+  ** with the new column name. All that remains is to construct and
+  ** return the edited SQL string. */
+  assert( nQuot>=nNew );
+  zOut = sqlite3DbMallocZero(db, nSql + pRename->nList*nQuot + 1);
+  if( zOut ){
+    int nOut = nSql;
+    memcpy(zOut, zSql, nSql);
+    while( pRename->pList ){
+      int iOff;                   /* Offset of token to replace in zOut */
+      RenameToken *pBest = renameColumnTokenNext(pRename);
+
+      u32 nReplace;
+      const char *zReplace;
+      if( sqlite3IsIdChar(*pBest->t.z) ){
+        nReplace = nNew;
+        zReplace = zNew;
+      }else{
+        nReplace = nQuot;
+        zReplace = zQuot;
+      }
+
+      iOff = pBest->t.z - zSql;
+      if( pBest->t.n!=nReplace ){
+        memmove(&zOut[iOff + nReplace], &zOut[iOff + pBest->t.n], 
+            nOut - (iOff + pBest->t.n)
+        );
+        nOut += nReplace - pBest->t.n;
+        zOut[nOut] = '\0';
+      }
+      memcpy(&zOut[iOff], zReplace, nReplace);
+      sqlite3DbFree(db, pBest);
+    }
+
+    sqlite3_result_text(pCtx, zOut, -1, SQLITE_TRANSIENT);
+    sqlite3DbFree(db, zOut);
+  }else{
+    rc = SQLITE_NOMEM;
+  }
+
+  sqlite3_free(zQuot);
+  return rc;
+}
+
+/*
+** Resolve all symbols in the trigger at pParse->pNewTrigger, assuming
+** it was read from the schema of database zDb. Return SQLITE_OK if 
+** successful. Otherwise, return an SQLite error code and leave an error
+** message in the Parse object.
+*/
+static int renameResolveTrigger(Parse *pParse, const char *zDb){
+  sqlite3 *db = pParse->db;
+  Trigger *pNew = pParse->pNewTrigger;
+  TriggerStep *pStep;
+  NameContext sNC;
+  int rc = SQLITE_OK;
+
+  memset(&sNC, 0, sizeof(sNC));
+  sNC.pParse = pParse;
+  assert( pNew->pTabSchema );
+  pParse->pTriggerTab = sqlite3FindTable(db, pNew->table, 
+      db->aDb[sqlite3SchemaToIndex(db, pNew->pTabSchema)].zDbSName
+  );
+  pParse->eTriggerOp = pNew->op;
+
+  /* Resolve symbols in WHEN clause */
+  if( pNew->pWhen ){
+    rc = sqlite3ResolveExprNames(&sNC, pNew->pWhen);
+  }
+
+  for(pStep=pNew->step_list; rc==SQLITE_OK && pStep; pStep=pStep->pNext){
+    if( pStep->pSelect ){
+      sqlite3SelectPrep(pParse, pStep->pSelect, &sNC);
+      if( pParse->nErr ) rc = pParse->rc;
+    }
+    if( rc==SQLITE_OK && pStep->zTarget ){
+      Table *pTarget = sqlite3LocateTable(pParse, 0, pStep->zTarget, zDb);
+      if( pTarget==0 ){
+        rc = SQLITE_ERROR;
+      }else if( SQLITE_OK==(rc = sqlite3ViewGetColumnNames(pParse, pTarget)) ){
+        SrcList sSrc;
+        memset(&sSrc, 0, sizeof(sSrc));
+        sSrc.nSrc = 1;
+        sSrc.a[0].zName = pStep->zTarget;
+        sSrc.a[0].pTab = pTarget;
+        sNC.pSrcList = &sSrc;
+        if( pStep->pWhere ){
+          rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere);
+        }
+        if( rc==SQLITE_OK ){
+          rc = sqlite3ResolveExprListNames(&sNC, pStep->pExprList);
+        }
+        assert( !pStep->pUpsert || (!pStep->pWhere && !pStep->pExprList) );
+        if( pStep->pUpsert ){
+          Upsert *pUpsert = pStep->pUpsert;
+          assert( rc==SQLITE_OK );
+          pUpsert->pUpsertSrc = &sSrc;
+          sNC.uNC.pUpsert = pUpsert;
+          sNC.ncFlags = NC_UUpsert;
+          rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
+          if( rc==SQLITE_OK ){
+            ExprList *pUpsertSet = pUpsert->pUpsertSet;
+            rc = sqlite3ResolveExprListNames(&sNC, pUpsertSet);
+          }
+          if( rc==SQLITE_OK ){
+            rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertWhere);
+          }
+          if( rc==SQLITE_OK ){
+            rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
+          }
+          sNC.ncFlags = 0;
+        }
+      }
+    }
+  }
+  return rc;
+}
+
+/*
+** Invoke sqlite3WalkExpr() or sqlite3WalkSelect() on all Select or Expr
+** objects that are part of the trigger passed as the second argument.
+*/
+static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){
+  TriggerStep *pStep;
+
+  /* Find tokens to edit in WHEN clause */
+  sqlite3WalkExpr(pWalker, pTrigger->pWhen);
+
+  /* Find tokens to edit in trigger steps */
+  for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){
+    sqlite3WalkSelect(pWalker, pStep->pSelect);
+    sqlite3WalkExpr(pWalker, pStep->pWhere);
+    sqlite3WalkExprList(pWalker, pStep->pExprList);
+    if( pStep->pUpsert ){
+      Upsert *pUpsert = pStep->pUpsert;
+      sqlite3WalkExprList(pWalker, pUpsert->pUpsertTarget);
+      sqlite3WalkExprList(pWalker, pUpsert->pUpsertSet);
+      sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere);
+      sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere);
+    }
+  }
+}
+
+/*
+** Free the contents of Parse object (*pParse). Do not free the memory
+** occupied by the Parse object itself.
+*/
+static void renameParseCleanup(Parse *pParse){
+  sqlite3 *db = pParse->db;
+  if( pParse->pVdbe ){
+    sqlite3VdbeFinalize(pParse->pVdbe);
+  }
+  sqlite3DeleteTable(db, pParse->pNewTable);
+  if( pParse->pNewIndex ) sqlite3FreeIndex(db, pParse->pNewIndex);
+  sqlite3DeleteTrigger(db, pParse->pNewTrigger);
+  sqlite3DbFree(db, pParse->zErrMsg);
+  renameTokenFree(db, pParse->pRename);
+  sqlite3ParserReset(pParse);
+}
+
+/*
+** SQL function:
+**
+**     sqlite_rename_column(zSql, iCol, bQuote, zNew, zTable, zOld)
+**
+**   0. zSql:     SQL statement to rewrite
+**   1. type:     Type of object ("table", "view" etc.)
+**   2. object:   Name of object
+**   3. Database: Database name (e.g. "main")
+**   4. Table:    Table name
+**   5. iCol:     Index of column to rename
+**   6. zNew:     New column name
+**   7. bQuote:   Non-zero if the new column name should be quoted.
+**   8. bTemp:    True if zSql comes from temp schema
+**
+** Do a column rename operation on the CREATE statement given in zSql.
+** The iCol-th column (left-most is 0) of table zTable is renamed from zCol
+** into zNew.  The name should be quoted if bQuote is true.
+**
+** This function is used internally by the ALTER TABLE RENAME COLUMN command.
+** Though accessible to application code, it is not intended for use by
+** applications.  The existance of this function, and the way it works,
+** is subject to change without notice.
+**
+** If any of the parameters are out-of-bounds, then simply return NULL.
+** An out-of-bounds parameter can only occur when the application calls
+** this function directly.  The parameters will always be well-formed when
+** this routine is invoked by the bytecode for a legitimate ALTER TABLE
+** statement.
+*/
+static void renameColumnFunc(
+  sqlite3_context *context,
+  int NotUsed,
+  sqlite3_value **argv
+){
+  sqlite3 *db = sqlite3_context_db_handle(context);
+  RenameCtx sCtx;
+  const char *zSql = (const char*)sqlite3_value_text(argv[0]);
+  const char *zDb = (const char*)sqlite3_value_text(argv[3]);
+  const char *zTable = (const char*)sqlite3_value_text(argv[4]);
+  int iCol = sqlite3_value_int(argv[5]);
+  const char *zNew = (const char*)sqlite3_value_text(argv[6]);
+  int bQuote = sqlite3_value_int(argv[7]);
+  int bTemp = sqlite3_value_int(argv[8]);
+  const char *zOld;
+  int rc;
+  Parse sParse;
+  Walker sWalker;
+  Index *pIdx;
+  int i;
+  Table *pTab;
+#ifndef SQLITE_OMIT_AUTHORIZATION
+  sqlite3_xauth xAuth = db->xAuth;
+#endif
+
+  UNUSED_PARAMETER(NotUsed);
+  if( zSql==0 ) return;
+  if( zTable==0 ) return;
+  if( zNew==0 ) return;
+  if( iCol<0 ) return;
+  sqlite3BtreeEnterAll(db);
+  pTab = sqlite3FindTable(db, zTable, zDb);
+  if( pTab==0 || iCol>=pTab->nCol ){
+    sqlite3BtreeLeaveAll(db);
+    return;
+  }
+  zOld = pTab->aCol[iCol].zName;
+  memset(&sCtx, 0, sizeof(sCtx));
+  sCtx.iCol = ((iCol==pTab->iPKey) ? -1 : iCol);
+
+#ifndef SQLITE_OMIT_AUTHORIZATION
+  db->xAuth = 0;
+#endif
+  rc = renameParseSql(&sParse, zDb, 0, db, zSql, bTemp);
+
+  /* Find tokens that need to be replaced. */
+  memset(&sWalker, 0, sizeof(Walker));
+  sWalker.pParse = &sParse;
+  sWalker.xExprCallback = renameColumnExprCb;
+  sWalker.xSelectCallback = renameColumnSelectCb;
+  sWalker.u.pRename = &sCtx;
+
+  sCtx.pTab = pTab;
+  if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
+  if( sParse.pNewTable ){
+    Select *pSelect = sParse.pNewTable->pSelect;
+    if( pSelect ){
+      sParse.rc = SQLITE_OK;
+      sqlite3SelectPrep(&sParse, sParse.pNewTable->pSelect, 0);
+      rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc);
+      if( rc==SQLITE_OK ){
+        sqlite3WalkSelect(&sWalker, pSelect);
+      }
+      if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
+    }else{
+      /* A regular table */
+      int bFKOnly = sqlite3_stricmp(zTable, sParse.pNewTable->zName);
+      FKey *pFKey;
+      assert( sParse.pNewTable->pSelect==0 );
+      sCtx.pTab = sParse.pNewTable;
+      if( bFKOnly==0 ){
+        renameTokenFind(
+            &sParse, &sCtx, (void*)sParse.pNewTable->aCol[iCol].zName
+        );
+        if( sCtx.iCol<0 ){
+          renameTokenFind(&sParse, &sCtx, (void*)&sParse.pNewTable->iPKey);
+        }
+        sqlite3WalkExprList(&sWalker, sParse.pNewTable->pCheck);
+        for(pIdx=sParse.pNewTable->pIndex; pIdx; pIdx=pIdx->pNext){
+          sqlite3WalkExprList(&sWalker, pIdx->aColExpr);
+        }
+      }
+
+      for(pFKey=sParse.pNewTable->pFKey; pFKey; pFKey=pFKey->pNextFrom){
+        for(i=0; i<pFKey->nCol; i++){
+          if( bFKOnly==0 && pFKey->aCol[i].iFrom==iCol ){
+            renameTokenFind(&sParse, &sCtx, (void*)&pFKey->aCol[i]);
+          }
+          if( 0==sqlite3_stricmp(pFKey->zTo, zTable)
+           && 0==sqlite3_stricmp(pFKey->aCol[i].zCol, zOld)
+          ){
+            renameTokenFind(&sParse, &sCtx, (void*)pFKey->aCol[i].zCol);
+          }
+        }
+      }
+    }
+  }else if( sParse.pNewIndex ){
+    sqlite3WalkExprList(&sWalker, sParse.pNewIndex->aColExpr);
+    sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere);
+  }else{
+    /* A trigger */
+    TriggerStep *pStep;
+    rc = renameResolveTrigger(&sParse, (bTemp ? 0 : zDb));
+    if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
+
+    for(pStep=sParse.pNewTrigger->step_list; pStep; pStep=pStep->pNext){
+      if( pStep->zTarget ){ 
+        Table *pTarget = sqlite3LocateTable(&sParse, 0, pStep->zTarget, zDb);
+        if( pTarget==pTab ){
+          if( pStep->pUpsert ){
+            ExprList *pUpsertSet = pStep->pUpsert->pUpsertSet;
+            renameColumnElistNames(&sParse, &sCtx, pUpsertSet, zOld);
+          }
+          renameColumnIdlistNames(&sParse, &sCtx, pStep->pIdList, zOld);
+          renameColumnElistNames(&sParse, &sCtx, pStep->pExprList, zOld);
+        }
+      }
+    }
+
+
+    /* Find tokens to edit in UPDATE OF clause */
+    if( sParse.pTriggerTab==pTab ){
+      renameColumnIdlistNames(&sParse, &sCtx,sParse.pNewTrigger->pColumns,zOld);
+    }
+
+    /* Find tokens to edit in various expressions and selects */
+    renameWalkTrigger(&sWalker, sParse.pNewTrigger);
+  }
+
+  assert( rc==SQLITE_OK );
+  rc = renameEditSql(context, &sCtx, zSql, zNew, bQuote);
+
+renameColumnFunc_done:
+  if( rc!=SQLITE_OK ){
+    if( sParse.zErrMsg ){
+      renameColumnParseError(context, 0, argv[1], argv[2], &sParse);
+    }else{
+      sqlite3_result_error_code(context, rc);
+    }
+  }
+
+  renameParseCleanup(&sParse);
+  renameTokenFree(db, sCtx.pList);
+#ifndef SQLITE_OMIT_AUTHORIZATION
+  db->xAuth = xAuth;
+#endif
+  sqlite3BtreeLeaveAll(db);
+}
+
+/*
+** Walker expression callback used by "RENAME TABLE". 
+*/
+static int renameTableExprCb(Walker *pWalker, Expr *pExpr){
+  RenameCtx *p = pWalker->u.pRename;
+  if( pExpr->op==TK_COLUMN && p->pTab==pExpr->pTab ){
+    renameTokenFind(pWalker->pParse, p, (void*)&pExpr->pTab);
+  }
+  return WRC_Continue;
+}
+
+/*
+** Walker select callback used by "RENAME TABLE". 
+*/
+static int renameTableSelectCb(Walker *pWalker, Select *pSelect){
+  int i;
+  RenameCtx *p = pWalker->u.pRename;
+  SrcList *pSrc = pSelect->pSrc;
+  for(i=0; i<pSrc->nSrc; i++){
+    struct SrcList_item *pItem = &pSrc->a[i];
+    if( pItem->pTab==p->pTab ){
+      renameTokenFind(pWalker->pParse, p, pItem->zName);
+    }
+  }
+
+  return WRC_Continue;
+}
+
+
+/*
+** 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:
+**
+**   0: The database containing the table being renamed.
+**   1. type:     Type of object ("table", "view" etc.)
+**   2. object:   Name of object
+**   3: The complete text of the schema statement being modified,
+**   4: The old name of the table being renamed, and
+**   5: The new name of the table being renamed.
+**   6: True if the schema statement comes from the temp db.
+**
+** It returns the new schema statement. For example:
+**
+** sqlite_rename_table('main', 'CREATE TABLE t1(a REFERENCES t2)','t2','t3',0)
+**       -> 'CREATE TABLE t1(a REFERENCES t3)'
+*/
+static void renameTableFunc(
+  sqlite3_context *context,
+  int NotUsed,
+  sqlite3_value **argv
+){
+  sqlite3 *db = sqlite3_context_db_handle(context);
+  const char *zDb = (const char*)sqlite3_value_text(argv[0]);
+  const char *zInput = (const char*)sqlite3_value_text(argv[3]);
+  const char *zOld = (const char*)sqlite3_value_text(argv[4]);
+  const char *zNew = (const char*)sqlite3_value_text(argv[5]);
+  int bTemp = sqlite3_value_int(argv[6]);
+  UNUSED_PARAMETER(NotUsed);
+
+  if( zInput && zOld && zNew ){
+    Parse sParse;
+    int rc;
+    int bQuote = 1;
+    RenameCtx sCtx;
+    Walker sWalker;
+
+#ifndef SQLITE_OMIT_AUTHORIZATION
+    sqlite3_xauth xAuth = db->xAuth;
+    db->xAuth = 0;
+#endif
+
+    sqlite3BtreeEnterAll(db);
+
+    memset(&sCtx, 0, sizeof(RenameCtx));
+    sCtx.pTab = sqlite3FindTable(db, zOld, zDb);
+    memset(&sWalker, 0, sizeof(Walker));
+    sWalker.pParse = &sParse;
+    sWalker.xExprCallback = renameTableExprCb;
+    sWalker.xSelectCallback = renameTableSelectCb;
+    sWalker.u.pRename = &sCtx;
+
+    rc = renameParseSql(&sParse, zDb, 1, db, zInput, bTemp);
+
+    if( rc==SQLITE_OK ){
+      if( sParse.pNewTable ){
+        Table *pTab = sParse.pNewTable;
+
+        if( pTab->pSelect ){
+          NameContext sNC;
+          memset(&sNC, 0, sizeof(sNC));
+          sNC.pParse = &sParse;
+
+          sqlite3SelectPrep(&sParse, pTab->pSelect, &sNC);
+          if( sParse.nErr ) rc = sParse.rc;
+          sqlite3WalkSelect(&sWalker, pTab->pSelect);
+        }else{
+          /* Modify any FK definitions to point to the new table. */
+#ifndef SQLITE_OMIT_FOREIGN_KEY
+          if( db->flags & SQLITE_ForeignKeys ){
+            FKey *pFKey;
+            for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){
+              if( sqlite3_stricmp(pFKey->zTo, zOld)==0 ){
+                renameTokenFind(&sParse, &sCtx, (void*)pFKey->zTo);
+              }
+            }
+          }
+#endif
+
+          /* If this is the table being altered, fix any table refs in CHECK
+          ** expressions. Also update the name that appears right after the
+          ** "CREATE [VIRTUAL] TABLE" bit. */
+          if( sqlite3_stricmp(zOld, pTab->zName)==0 ){
+            sCtx.pTab = pTab;
+            sqlite3WalkExprList(&sWalker, pTab->pCheck);
+            renameTokenFind(&sParse, &sCtx, pTab->zName);
+          }
+        }
+      }
+
+      else if( sParse.pNewIndex ){
+        renameTokenFind(&sParse, &sCtx, sParse.pNewIndex->zName);
+        sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere);
+      }
+
+#ifndef SQLITE_OMIT_TRIGGER
+      else{
+        Trigger *pTrigger = sParse.pNewTrigger;
+        TriggerStep *pStep;
+        if( 0==sqlite3_stricmp(sParse.pNewTrigger->table, zOld) 
+            && sCtx.pTab->pSchema==pTrigger->pTabSchema
+          ){
+          renameTokenFind(&sParse, &sCtx, sParse.pNewTrigger->table);
+        }
+
+        rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb);
+        if( rc==SQLITE_OK ){
+          renameWalkTrigger(&sWalker, pTrigger);
+          for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){
+            if( pStep->zTarget && 0==sqlite3_stricmp(pStep->zTarget, zOld) ){
+              renameTokenFind(&sParse, &sCtx, pStep->zTarget);
+            }
+          }
+        }
+      }
+#endif
+    }
+
+    if( rc==SQLITE_OK ){
+      rc = renameEditSql(context, &sCtx, zInput, zNew, bQuote);
+    }
+    if( rc!=SQLITE_OK ){
+      if( sParse.zErrMsg ){
+        renameColumnParseError(context, 0, argv[1], argv[2], &sParse);
+      }else{
+        sqlite3_result_error_code(context, rc);
+      }
+    }
+
+    renameParseCleanup(&sParse);
+    renameTokenFree(db, sCtx.pList);
+    sqlite3BtreeLeaveAll(db);
+#ifndef SQLITE_OMIT_AUTHORIZATION
+    db->xAuth = xAuth;
+#endif
+  }
+
+  return;
+}
+
+/*
+** An SQL user function that checks that there are no parse or symbol
+** resolution problems in a CREATE TRIGGER|TABLE|VIEW|INDEX statement.
+** After an ALTER TABLE .. RENAME operation is performed and the schema
+** reloaded, this function is called on each SQL statement in the schema
+** to ensure that it is still usable.
+**
+**   0: Database name ("main", "temp" etc.).
+**   1: SQL statement.
+**   2: Object type ("view", "table", "trigger" or "index").
+**   3: Object name.
+**   4: True if object is from temp schema.
+**
+** Unless it finds an error, this function normally returns NULL. However, it
+** returns integer value 1 if:
+**
+**   * the SQL argument creates a trigger, and
+**   * the table that the trigger is attached to is in database zDb.
+*/
+static void renameTableTest(
+  sqlite3_context *context,
+  int NotUsed,
+  sqlite3_value **argv
+){
+  sqlite3 *db = sqlite3_context_db_handle(context);
+  char const *zDb = (const char*)sqlite3_value_text(argv[0]);
+  char const *zInput = (const char*)sqlite3_value_text(argv[1]);
+  int bTemp = sqlite3_value_int(argv[4]);
+
+#ifndef SQLITE_OMIT_AUTHORIZATION
+  sqlite3_xauth xAuth = db->xAuth;
+  db->xAuth = 0;
+#endif
+
+  UNUSED_PARAMETER(NotUsed);
+  if( zDb && zInput ){
+    int rc;
+    Parse sParse;
+    rc = renameParseSql(&sParse, zDb, 1, db, zInput, bTemp);
+    if( rc==SQLITE_OK ){
+      if( sParse.pNewTable && sParse.pNewTable->pSelect ){
+        NameContext sNC;
+        memset(&sNC, 0, sizeof(sNC));
+        sNC.pParse = &sParse;
+        sqlite3SelectPrep(&sParse, sParse.pNewTable->pSelect, &sNC);
+        if( sParse.nErr ) rc = sParse.rc;
+      }
+
+      else if( sParse.pNewTrigger ){
+        rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb);
+        if( rc==SQLITE_OK ){
+          int i1 = sqlite3SchemaToIndex(db, sParse.pNewTrigger->pTabSchema);
+          int i2 = sqlite3FindDbName(db, zDb);
+          if( i1==i2 ) sqlite3_result_int(context, 1);
+        }
+      }
+    }
+
+    if( rc!=SQLITE_OK ){
+      renameColumnParseError(context, 1, argv[2], argv[3], &sParse);
+    }
+    renameParseCleanup(&sParse);
+  }
+
+#ifndef SQLITE_OMIT_AUTHORIZATION
+  db->xAuth = xAuth;
+#endif
+}
+
+/*
+** Register built-in functions used to help implement ALTER TABLE
+*/
+SQLITE_PRIVATE void sqlite3AlterFunctions(void){
+  static FuncDef aAlterTableFuncs[] = {
+    FUNCTION(sqlite_rename_column,  9, 0, 0, renameColumnFunc),
+    FUNCTION(sqlite_rename_table,  7, 0, 0, renameTableFunc),
+    FUNCTION(sqlite_rename_test,  5, 0, 0, renameTableTest),
+  };
+  sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs));
+}
 #endif  /* SQLITE_ALTER_TABLE */
 
 /************** End of alter.c ***********************************************/
@@ -101566,6 +103207,7 @@ static const FuncDef statInitFuncdef = {
   0,               /* pNext */
   statInit,        /* xSFunc */
   0,               /* xFinalize */
+  0, 0,            /* xValue, xInverse */
   "stat_init",     /* zName */
   {0}
 };
@@ -101882,6 +103524,7 @@ static const FuncDef statPushFuncdef = {
   0,               /* pNext */
   statPush,        /* xSFunc */
   0,               /* xFinalize */
+  0, 0,            /* xValue, xInverse */
   "stat_push",     /* zName */
   {0}
 };
@@ -102033,6 +103676,7 @@ static const FuncDef statGetFuncdef = {
   0,               /* pNext */
   statGet,         /* xSFunc */
   0,               /* xFinalize */
+  0, 0,            /* xValue, xInverse */
   "stat_get",      /* zName */
   {0}
 };
@@ -102352,10 +103996,7 @@ static void analyzeOneTable(
       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);
+      VdbeCoverage(v);
 #ifdef SQLITE_ENABLE_STAT3
       sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, 0, regSample);
 #else
@@ -102995,7 +104636,7 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
 
   /* Load the statistics from the sqlite_stat4 table. */
 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
-  if( rc==SQLITE_OK && OptimizationEnabled(db, SQLITE_Stat34) ){
+  if( rc==SQLITE_OK ){
     db->lookaside.bDisable++;
     rc = loadStat4(db, sInfo.zDatabase);
     db->lookaside.bDisable--;
@@ -103434,6 +105075,7 @@ SQLITE_PRIVATE void sqlite3Detach(Parse *pParse, Expr *pDbname){
     0,                /* pNext */
     detachFunc,       /* xSFunc */
     0,                /* xFinalize */
+    0, 0,             /* xValue, xInverse */
     "sqlite_detach",  /* zName */
     {0}
   };
@@ -103453,6 +105095,7 @@ SQLITE_PRIVATE void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *p
     0,                /* pNext */
     attachFunc,       /* xSFunc */
     0,                /* xFinalize */
+    0, 0,             /* xValue, xInverse */
     "sqlite_attach",  /* zName */
     {0}
   };
@@ -103725,7 +105368,7 @@ SQLITE_API int sqlite3_set_authorizer(
   sqlite3_mutex_enter(db->mutex);
   db->xAuth = (sqlite3_xauth)xAuth;
   db->pAuthArg = pArg;
-  sqlite3ExpirePreparedStatements(db);
+  sqlite3ExpirePreparedStatements(db, 0);
   sqlite3_mutex_leave(db->mutex);
   return SQLITE_OK;
 }
@@ -103854,7 +105497,7 @@ SQLITE_PRIVATE int sqlite3AuthCheck(
   /* 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 ){
+  if( db->init.busy || IN_SPECIAL_PARSE ){
     return SQLITE_OK;
   }
 
@@ -104146,7 +105789,6 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
   /* 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;
@@ -104361,7 +106003,7 @@ SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const cha
 /*
 ** Reclaim the memory used by an index
 */
-static void freeIndex(sqlite3 *db, Index *p){
+SQLITE_PRIVATE void sqlite3FreeIndex(sqlite3 *db, Index *p){
 #ifndef SQLITE_OMIT_ANALYZE
   sqlite3DeleteIndexSamples(db, p);
 #endif
@@ -104401,7 +106043,7 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char
         p->pNext = pIndex->pNext;
       }
     }
-    freeIndex(db, pIndex);
+    sqlite3FreeIndex(db, pIndex);
   }
   db->mDbFlags |= DBFLAG_SchemaChange;
 }
@@ -104547,7 +106189,7 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
       assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
       assert( pOld==pIndex || pOld==0 );
     }
-    freeIndex(db, pIndex);
+    sqlite3FreeIndex(db, pIndex);
   }
 
   /* Delete any foreign keys attached to this table. */
@@ -104705,7 +106347,7 @@ SQLITE_PRIVATE int sqlite3TwoPartName(
       return -1;
     }
   }else{
-    assert( db->init.iDb==0 || db->init.busy
+    assert( db->init.iDb==0 || db->init.busy || IN_RENAME_OBJECT
              || (db->mDbFlags & DBFLAG_Vacuum)!=0);
     iDb = db->init.iDb;
     *pUnqual = pName1;
@@ -104800,6 +106442,9 @@ SQLITE_PRIVATE void sqlite3StartTable(
     }
     if( !OMIT_TEMPDB && isTemp ) iDb = 1;
     zName = sqlite3NameFromToken(db, pName);
+    if( IN_RENAME_OBJECT ){
+      sqlite3RenameTokenMap(pParse, (void*)zName, pName);
+    }
   }
   pParse->sNameToken = *pName;
   if( zName==0 ) return;
@@ -104835,7 +106480,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
   ** and types will be used, so there is no need to test for namespace
   ** collisions.
   */
-  if( !IN_DECLARE_VTAB ){
+  if( !IN_SPECIAL_PARSE ){
     char *zDb = db->aDb[iDb].zDbSName;
     if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
       goto begin_table_error;
@@ -104994,6 +106639,7 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
   }
   z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2);
   if( z==0 ) return;
+  if( IN_RENAME_OBJECT ) sqlite3RenameTokenMap(pParse, (void*)z, pName);
   memcpy(z, pName->z, pName->n);
   z[pName->n] = 0;
   sqlite3Dequote(z);
@@ -105200,6 +106846,9 @@ SQLITE_PRIVATE void sqlite3AddDefaultValue(
       sqlite3DbFree(db, x.u.zToken);
     }
   }
+  if( IN_RENAME_OBJECT ){
+    sqlite3RenameExprUnmap(pParse, pExpr);
+  }
   sqlite3ExprDelete(db, pExpr);
 }
 
@@ -105291,6 +106940,9 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
    && sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0
    && sortOrder!=SQLITE_SO_DESC
   ){
+    if( IN_RENAME_OBJECT && pList ){
+      sqlite3RenameTokenRemap(pParse, &pTab->iPKey, pList->a[0].pExpr);
+    }
     pTab->iPKey = iCol;
     pTab->keyConf = (u8)onError;
     assert( autoInc==0 || autoInc==1 );
@@ -105616,6 +107268,31 @@ static int hasColumn(const i16 *aiCol, int nCol, int x){
   return 0;
 }
 
+/* Recompute the colNotIdxed field of the Index.
+**
+** colNotIdxed is a bitmask that has a 0 bit representing each indexed
+** columns that are within the first 63 columns of the table.  The
+** high-order bit of colNotIdxed is always 1.  All unindexed columns
+** of the table have a 1.
+**
+** The colNotIdxed mask is AND-ed with the SrcList.a[].colUsed mask
+** to determine if the index is covering index.
+*/
+static void recomputeColumnsNotIndexed(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( x<BMS-1 ) m |= MASKBIT(x);
+    }
+  }
+  pIdx->colNotIdxed = ~m;
+  assert( (pIdx->colNotIdxed>>63)==1 );
+}
+
 /*
 ** 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
@@ -105684,7 +107361,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
     assert( pParse->pNewTable==pTab );
     sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0,
                        SQLITE_IDXTYPE_PRIMARYKEY);
-    if( db->mallocFailed ) return;
+    if( db->mallocFailed || pParse->nErr ) return;
     pPk = sqlite3PrimaryKeyIndex(pTab);
     pTab->iPKey = -1;
   }else{
@@ -105764,6 +107441,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
   }else{
     pPk->nColumn = pTab->nCol;
   }
+  recomputeColumnsNotIndexed(pPk);
 }
 
 /*
@@ -106067,7 +107745,12 @@ SQLITE_PRIVATE void sqlite3CreateView(
   ** 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);
+  if( IN_RENAME_OBJECT ){
+    p->pSelect = pSelect;
+    pSelect = 0;
+  }else{
+    p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
+  }
   p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE);
   if( db->mallocFailed ) goto create_view_fail;
 
@@ -106092,6 +107775,9 @@ SQLITE_PRIVATE void sqlite3CreateView(
 
 create_view_fail:
   sqlite3SelectDelete(db, pSelect);
+  if( IN_RENAME_OBJECT ){
+    sqlite3RenameExprlistUnmap(pParse, pCNames);
+  }
   sqlite3ExprListDelete(db, pCNames);
   return;
 }
@@ -106165,6 +107851,10 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
   assert( pTable->pSelect );
   pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
   if( pSel ){
+#ifndef SQLITE_OMIT_ALTERTABLE
+    u8 eParseMode = pParse->eParseMode;
+    pParse->eParseMode = PARSE_MODE_NORMAL;
+#endif
     n = pParse->nTab;
     sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
     pTable->nCol = -1;
@@ -106210,10 +107900,18 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
     sqlite3DeleteTable(db, pSelTab);
     sqlite3SelectDelete(db, pSel);
     db->lookaside.bDisable--;
+#ifndef SQLITE_OMIT_ALTERTABLE
+    pParse->eParseMode = eParseMode;
+#endif
   } else {
     nErr++;
   }
   pTable->pSchema->schemaFlags |= DB_UnresetViews;
+  if( db->mallocFailed ){
+    sqlite3DeleteColumnNames(db, pTable);
+    pTable->aCol = 0;
+    pTable->nCol = 0;
+  }
 #endif /* SQLITE_OMIT_VIEW */
   return nErr;  
 }
@@ -106552,8 +108250,10 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView,
   v = sqlite3GetVdbe(pParse);
   if( v ){
     sqlite3BeginWriteOperation(pParse, 1, iDb);
-    sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName);
-    sqlite3FkDropTable(pParse, pName, pTab);
+    if( !isView ){
+      sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName);
+      sqlite3FkDropTable(pParse, pName, pTab);
+    }
     sqlite3CodeDropTable(pParse, pTab, iDb, isView);
   }
 
@@ -106628,6 +108328,9 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey(
   pFKey->pNextFrom = p->pFKey;
   z = (char*)&pFKey->aCol[nCol];
   pFKey->zTo = z;
+  if( IN_RENAME_OBJECT ){
+    sqlite3RenameTokenMap(pParse, (void*)z, pTo);
+  }
   memcpy(z, pTo->z, pTo->n);
   z[pTo->n] = 0;
   sqlite3Dequote(z);
@@ -106650,12 +108353,18 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey(
           pFromCol->a[i].zName);
         goto fk_end;
       }
+      if( IN_RENAME_OBJECT ){
+        sqlite3RenameTokenRemap(pParse, &pFKey->aCol[i], pFromCol->a[i].zName);
+      }
     }
   }
   if( pToCol ){
     for(i=0; i<nCol; i++){
       int n = sqlite3Strlen30(pToCol->a[i].zName);
       pFKey->aCol[i].zCol = z;
+      if( IN_RENAME_OBJECT ){
+        sqlite3RenameTokenRemap(pParse, z, pToCol->a[i].zName);
+      }
       memcpy(z, pToCol->a[i].zName, n);
       z[n] = 0;
       z += n+1;
@@ -106988,20 +108697,22 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
     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( !IN_RENAME_OBJECT ){
+      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);
+      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;
       }
-      goto exit_create_index;
     }
   }else{
     int n;
@@ -107017,13 +108728,13 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
     ** 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]++;
+    if( IN_SPECIAL_PARSE ) zName[7]++;
   }
 
   /* Check for authorization to create an index.
   */
 #ifndef SQLITE_OMIT_AUTHORIZATION
-  {
+  if( !IN_RENAME_OBJECT ){
     const char *zDb = pDb->zDbSName;
     if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){
       goto exit_create_index;
@@ -107110,7 +108821,12 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
   ** TODO: Issue a warning if the table primary key is used as part of the
   ** index key.
   */
-  for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){
+  pListItem = pList->a;
+  if( IN_RENAME_OBJECT ){
+    pIndex->aColExpr = pList;
+    pList = 0;
+  }
+  for(i=0; i<pIndex->nKeyCol; 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 */
@@ -107126,12 +108842,8 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
         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];
-        }
+        pIndex->aColExpr = pList;
+        pList = 0;
       }
       j = XN_EXPR;
       pIndex->aiColumn[i] = XN_EXPR;
@@ -107197,6 +108909,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
   ** it as a covering index */
   assert( HasRowid(pTab) 
       || pTab->iPKey<0 || sqlite3ColumnOfIndex(pIndex, pTab->iPKey)>=0 );
+  recomputeColumnsNotIndexed(pIndex);
   if( pTblName!=0 && pIndex->nColumn>=pTab->nCol ){
     pIndex->isCovering = 1;
     for(j=0; j<pTab->nCol; j++){
@@ -107269,98 +108982,101 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
     }
   }
 
-  /* 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->mDbFlags |= DBFLAG_SchemaChange;
-    if( pTblName!=0 ){
-      pIndex->tnum = db->init.newTnum;
-    }
-  }
+  if( !IN_RENAME_OBJECT ){
 
-  /* 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);
-    sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY);
-
-    /* Gather the complete text of the CREATE INDEX statement into
-    ** the zStmt variable
+    /* Link the new Index structure to its table and to the other
+    ** in-memory database structures. 
     */
-    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;
+    assert( pParse->nErr==0 );
+    if( db->init.busy ){
+      Index *p;
+      assert( !IN_SPECIAL_PARSE );
+      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->mDbFlags |= DBFLAG_SchemaChange;
+      if( pTblName!=0 ){
+        pIndex->tnum = db->init.newTnum;
+      }
     }
 
-    /* Add an entry in sqlite_master for this index
+    /* 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.
     */
-    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);
+    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);
+      sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY);
+
+      /* 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;
+      }
 
-    /* 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);
-    }
+      /* 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);
 
-    sqlite3VdbeJumpHere(v, pIndex->tnum);
+      /* 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));
+        sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
+      }
+
+      sqlite3VdbeJumpHere(v, pIndex->tnum);
+    }
   }
 
   /* When adding an index to the list of indices for a table, make
@@ -107384,10 +109100,15 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
     }
     pIndex = 0;
   }
+  else if( IN_RENAME_OBJECT ){
+    assert( pParse->pNewIndex==0 );
+    pParse->pNewIndex = pIndex;
+    pIndex = 0;
+  }
 
   /* Clean up before exiting */
 exit_create_index:
-  if( pIndex ) freeIndex(db, pIndex);
+  if( pIndex ) sqlite3FreeIndex(db, pIndex);
   sqlite3ExprDelete(db, pPIWhere);
   sqlite3ExprListDelete(db, pList);
   sqlite3SrcListDelete(db, pTblName);
@@ -107556,7 +109277,8 @@ SQLITE_PRIVATE void *sqlite3ArrayAllocate(
 **
 ** A new IdList is returned, or NULL if malloc() fails.
 */
-SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pToken){
+SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *pToken){
+  sqlite3 *db = pParse->db;
   int i;
   if( pList==0 ){
     pList = sqlite3DbMallocZero(db, sizeof(IdList) );
@@ -107574,6 +109296,9 @@ SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pT
     return 0;
   }
   pList->a[i].zName = sqlite3NameFromToken(db, pToken);
+  if( IN_RENAME_OBJECT && pList->a[i].zName ){
+    sqlite3RenameTokenMap(pParse, (void*)pList->a[i].zName, pToken);
+  }
   return pList;
 }
 
@@ -107820,6 +109545,12 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(
   }
   assert( p->nSrc>0 );
   pItem = &p->a[p->nSrc-1];
+  assert( (pTable==0)==(pDatabase==0) );
+  assert( pItem->zName==0 || pDatabase!=0 );
+  if( IN_RENAME_OBJECT && pItem->zName ){
+    Token *pToken = (ALWAYS(pDatabase) && pDatabase->z) ? pDatabase : pTable;
+    sqlite3RenameTokenMap(pParse, pItem->zName, pToken);
+  }
   assert( pAlias!=0 );
   if( pAlias->n ){
     pItem->zAlias = sqlite3NameFromToken(db, pAlias);
@@ -109373,9 +111104,8 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
       }
       iKey = iPk;
     }else{
-      iKey = pParse->nMem + 1;
-      iKey = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iTabCur, iKey, 0);
-      if( iKey>pParse->nMem ) pParse->nMem = iKey;
+      iKey = ++pParse->nMem;
+      sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, -1, iKey);
     }
   
     if( eOnePass!=ONEPASS_OFF ){
@@ -109808,7 +111538,6 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey(
     if( pIdx->pPartIdxWhere ){
       *piPartIdxLabel = sqlite3VdbeMakeLabel(v);
       pParse->iSelfTab = iDataCur + 1;
-      sqlite3ExprCachePush(pParse);
       sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, 
                             SQLITE_JUMPIFNULL);
       pParse->iSelfTab = 0;
@@ -109855,7 +111584,6 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey(
 SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse *pParse, int iLabel){
   if( iLabel ){
     sqlite3VdbeResolveLabel(pParse->pVdbe, iLabel);
-    sqlite3ExprCachePop(pParse);
   }
 }
 
@@ -111368,7 +113096,7 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
       i64 v = sqlite3_value_int64(argv[0]);
       p->rSum += v;
       if( (p->approx|p->overflow)==0 && sqlite3AddInt64(&p->iSum, v) ){
-        p->overflow = 1;
+        p->approx = p->overflow = 1;
       }
     }else{
       p->rSum += sqlite3_value_double(argv[0]);
@@ -111376,6 +113104,32 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
     }
   }
 }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+static void sumInverse(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]);
+  /* p is always non-NULL because sumStep() will have been called first
+  ** to initialize it */
+  if( ALWAYS(p) && type!=SQLITE_NULL ){
+    assert( p->cnt>0 );
+    p->cnt--;
+    assert( type==SQLITE_INTEGER || p->approx );
+    if( type==SQLITE_INTEGER && p->approx==0 ){
+      i64 v = sqlite3_value_int64(argv[0]);
+      p->rSum -= v;
+      p->iSum -= v;
+    }else{
+      p->rSum -= sqlite3_value_double(argv[0]);
+    }
+  }
+}
+#else
+# define sumInverse 0
+#endif /* SQLITE_OMIT_WINDOWFUNC */
 static void sumFinalize(sqlite3_context *context){
   SumCtx *p;
   p = sqlite3_aggregate_context(context, 0);
@@ -111410,6 +113164,9 @@ static void totalFinalize(sqlite3_context *context){
 typedef struct CountCtx CountCtx;
 struct CountCtx {
   i64 n;
+#ifdef SQLITE_DEBUG
+  int bInverse;                   /* True if xInverse() ever called */
+#endif
 };
 
 /*
@@ -111427,7 +113184,7 @@ static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
   ** 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
+  assert( argc==1 || p==0 || p->n>0x7fffffff || p->bInverse
           || p->n==sqlite3_aggregate_count(context) );
 #endif
 }   
@@ -111436,6 +113193,21 @@ static void countFinalize(sqlite3_context *context){
   p = sqlite3_aggregate_context(context, 0);
   sqlite3_result_int64(context, p ? p->n : 0);
 }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+static void countInverse(sqlite3_context *ctx, int argc, sqlite3_value **argv){
+  CountCtx *p;
+  p = sqlite3_aggregate_context(ctx, sizeof(*p));
+  /* p is always non-NULL since countStep() will have been called first */
+  if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0])) && ALWAYS(p) ){
+    p->n--;
+#ifdef SQLITE_DEBUG
+    p->bInverse = 1;
+#endif
+  }
+}   
+#else
+# define countInverse 0
+#endif /* SQLITE_OMIT_WINDOWFUNC */
 
 /*
 ** Routines to implement min() and max() aggregate functions.
@@ -111452,7 +113224,7 @@ static void minmaxStep(
   pBest = (Mem *)sqlite3_aggregate_context(context, sizeof(*pBest));
   if( !pBest ) return;
 
-  if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
+  if( sqlite3_value_type(pArg)==SQLITE_NULL ){
     if( pBest->flags ) sqlite3SkipAccumulatorLoad(context);
   }else if( pBest->flags ){
     int max;
@@ -111478,16 +113250,26 @@ static void minmaxStep(
     sqlite3VdbeMemCopy(pBest, pArg);
   }
 }
-static void minMaxFinalize(sqlite3_context *context){
+static void minMaxValueFinalize(sqlite3_context *context, int bValue){
   sqlite3_value *pRes;
   pRes = (sqlite3_value *)sqlite3_aggregate_context(context, 0);
   if( pRes ){
     if( pRes->flags ){
       sqlite3_result_value(context, pRes);
     }
-    sqlite3VdbeMemRelease(pRes);
+    if( bValue==0 ) sqlite3VdbeMemRelease(pRes);
   }
 }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+static void minMaxValue(sqlite3_context *context){
+  minMaxValueFinalize(context, 1);
+}
+#else
+# define minMaxValue 0
+#endif /* SQLITE_OMIT_WINDOWFUNC */
+static void minMaxFinalize(sqlite3_context *context){
+  minMaxValueFinalize(context, 0);
+}
 
 /*
 ** group_concat(EXPR, ?SEPARATOR?)
@@ -111524,6 +113306,38 @@ static void groupConcatStep(
     if( zVal ) sqlite3_str_append(pAccum, zVal, nVal);
   }
 }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+static void groupConcatInverse(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  int n;
+  StrAccum *pAccum;
+  assert( argc==1 || argc==2 );
+  if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
+  pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum));
+  /* pAccum is always non-NULL since groupConcatStep() will have always
+  ** run frist to initialize it */
+  if( ALWAYS(pAccum) ){
+    n = sqlite3_value_bytes(argv[0]);
+    if( argc==2 ){
+      n += sqlite3_value_bytes(argv[1]);
+    }else{
+      n++;
+    }
+    if( n>=(int)pAccum->nChar ){
+      pAccum->nChar = 0;
+    }else{
+      pAccum->nChar -= n;
+      memmove(pAccum->zText, &pAccum->zText[n], pAccum->nChar);
+    }
+    if( pAccum->nChar==0 ) pAccum->mxAlloc = 0;
+  }
+}
+#else
+# define groupConcatInverse 0
+#endif /* SQLITE_OMIT_WINDOWFUNC */
 static void groupConcatFinalize(sqlite3_context *context){
   StrAccum *pAccum;
   pAccum = sqlite3_aggregate_context(context, 0);
@@ -111538,6 +113352,24 @@ static void groupConcatFinalize(sqlite3_context *context){
     }
   }
 }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+static void groupConcatValue(sqlite3_context *context){
+  sqlite3_str *pAccum;
+  pAccum = (sqlite3_str*)sqlite3_aggregate_context(context, 0);
+  if( pAccum ){
+    if( pAccum->accError==SQLITE_TOOBIG ){
+      sqlite3_result_error_toobig(context);
+    }else if( pAccum->accError==SQLITE_NOMEM ){
+      sqlite3_result_error_nomem(context);
+    }else{    
+      const char *zText = sqlite3_str_value(pAccum);
+      sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT);
+    }
+  }
+}
+#else
+# define groupConcatValue 0
+#endif /* SQLITE_OMIT_WINDOWFUNC */
 
 /*
 ** This routine does per-connection function registration.  Most
@@ -111575,10 +113407,10 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive)
   }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, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0);
+  sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0);
   sqlite3CreateFunc(db, "glob", 2, SQLITE_UTF8, 
-      (struct compareInfo*)&globInfo, likeFunc, 0, 0, 0);
+      (struct compareInfo*)&globInfo, likeFunc, 0, 0, 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);
@@ -111687,11 +113519,11 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
     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,
+    WAGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize, minMaxValue, 0,
                                           SQLITE_FUNC_MINMAX ),
     FUNCTION(max,               -1, 1, 1, minmaxFunc       ),
     FUNCTION(max,                0, 1, 1, 0                ),
-    AGGREGATE2(max,              1, 1, 1, minmaxStep,      minMaxFinalize,
+    WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0,
                                           SQLITE_FUNC_MINMAX ),
     FUNCTION2(typeof,            1, 0, 0, typeofFunc,  SQLITE_FUNC_TYPEOF),
     FUNCTION2(length,            1, 0, 0, lengthFunc,  SQLITE_FUNC_LENGTH),
@@ -111722,14 +113554,17 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
     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),
+    WAGGREGATE(sum,   1,0,0, sumStep, sumFinalize, sumFinalize, sumInverse, 0),
+    WAGGREGATE(total, 1,0,0, sumStep,totalFinalize,totalFinalize,sumInverse, 0),
+    WAGGREGATE(avg,   1,0,0, sumStep, avgFinalize, avgFinalize, sumInverse, 0),
+    WAGGREGATE(count, 0,0,0, countStep, 
+        countFinalize, countFinalize, countInverse, SQLITE_FUNC_COUNT  ),
+    WAGGREGATE(count, 1,0,0, countStep, 
+        countFinalize, countFinalize, countInverse, 0  ),
+    WAGGREGATE(group_concat, 1, 0, 0, groupConcatStep, 
+        groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
+    WAGGREGATE(group_concat, 2, 0, 0, groupConcatStep, 
+        groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
   
     LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
 #ifdef SQLITE_CASE_SENSITIVE_LIKE
@@ -111749,6 +113584,7 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
 #ifndef SQLITE_OMIT_ALTERTABLE
   sqlite3AlterFunctions();
 #endif
+  sqlite3WindowFunctions();
 #if defined(SQLITE_ENABLE_STAT3) || defined(SQLITE_ENABLE_STAT4)
   sqlite3AnalyzeFunctions();
 #endif
@@ -112486,11 +114322,12 @@ static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){
 */
 SQLITE_PRIVATE void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
   sqlite3 *db = pParse->db;
-  if( (db->flags&SQLITE_ForeignKeys) && !IsVirtual(pTab) && !pTab->pSelect ){
+  if( (db->flags&SQLITE_ForeignKeys) && !IsVirtual(pTab) ){
     int iSkip = 0;
     Vdbe *v = sqlite3GetVdbe(pParse);
 
     assert( v );                  /* VDBE has already been allocated */
+    assert( pTab->pSelect==0 );   /* Not a view */
     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 
@@ -114385,44 +116222,6 @@ static int checkConstraintUnchanged(Expr *pExpr, int *aiChng, int chngRowid){
   return !w.eCode;
 }
 
-/*
-** An instance of the ConstraintAddr object remembers the byte-code addresses
-** for sections of the constraint checks that deal with uniqueness constraints
-** on the rowid and on the upsert constraint.
-**
-** This information is passed into checkReorderConstraintChecks() to insert
-** some OP_Goto operations so that the rowid and upsert constraints occur
-** in the correct order relative to other constraints.
-*/
-typedef struct ConstraintAddr ConstraintAddr;
-struct ConstraintAddr {
-  int ipkTop;          /* Subroutine for rowid constraint check */
-  int upsertTop;       /* Label for upsert constraint check subroutine */
-  int upsertTop2;      /* Copy of upsertTop not cleared by the call */
-  int upsertBtm;       /* upsert constraint returns to this label */
-  int ipkBtm;          /* Return opcode rowid constraint check */
-};
-
-/*
-** Generate any OP_Goto operations needed to cause constraints to be
-** run that haven't already been run.
-*/
-static void reorderConstraintChecks(Vdbe *v, ConstraintAddr *p){
-  if( p->upsertTop ){
-    testcase( sqlite3VdbeLabelHasBeenResolved(v, p->upsertTop) );
-    sqlite3VdbeGoto(v, p->upsertTop);
-    VdbeComment((v, "call upsert subroutine"));
-    sqlite3VdbeResolveLabel(v, p->upsertBtm);
-    p->upsertTop = 0;
-  }
-  if( p->ipkTop ){
-    sqlite3VdbeGoto(v, p->ipkTop);
-    VdbeComment((v, "call rowid unique-check subroutine"));
-    sqlite3VdbeJumpHere(v, p->ipkBtm);
-    p->ipkTop = 0;
-  }
-}
-
 /*
 ** Generate code to do constraint checks prior to an INSERT or an UPDATE
 ** on table pTab.
@@ -114532,11 +116331,13 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
   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 */
-  ConstraintAddr sAddr;/* Address information for constraint reordering */
   Index *pUpIdx = 0;   /* Index to which to apply the upsert */
   u8 isUpdate;         /* True if this is an UPDATE operation */
   u8 bAffinityDone = 0;  /* True if the OP_Affinity operation has been run */
   int upsertBypass = 0;  /* Address of Goto to bypass upsert subroutine */
+  int upsertJump = 0;    /* Address of Goto that jumps into upsert subroutine */
+  int ipkTop = 0;        /* Top of the IPK uniqueness check */
+  int ipkBottom = 0;     /* OP_Goto at the end of the IPK uniqueness check */
 
   isUpdate = regOldData!=0;
   db = pParse->db;
@@ -114544,7 +116345,6 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
   assert( v!=0 );
   assert( pTab->pSelect==0 );  /* This table is not a VIEW */
   nCol = pTab->nCol;
-  memset(&sAddr, 0, sizeof(sAddr));
   
   /* 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 
@@ -114648,8 +116448,8 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
   /* UNIQUE and PRIMARY KEY constraints should be handled in the following
   ** order:
   **
-  **   (1)  OE_Abort, OE_Fail, OE_Rollback, OE_Ignore
-  **   (2)  OE_Update
+  **   (1)  OE_Update
+  **   (2)  OE_Abort, OE_Fail, OE_Rollback, OE_Ignore
   **   (3)  OE_Replace
   **
   ** OE_Fail and OE_Ignore must happen before any changes are made.
@@ -114658,6 +116458,11 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
   ** could happen in any order, but they are grouped up front for
   ** convenience.
   **
+  ** 2018-08-14: Ticket https://www.sqlite.org/src/info/908f001483982c43
+  ** The order of constraints used to have OE_Update as (2) and OE_Abort
+  ** and so forth as (1). But apparently PostgreSQL checks the OE_Update
+  ** constraint before any others, so it had to be moved.
+  **
   ** Constraint checking code is generated in this order:
   **   (A)  The rowid constraint
   **   (B)  Unique index constraints that do not have OE_Replace as their
@@ -114677,11 +116482,10 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
       overrideError = OE_Ignore;
       pUpsert = 0;
     }else if( (pUpIdx = pUpsert->pUpsertIdx)!=0 ){
-      /* If the constraint-target is on some column other than
-      ** then ROWID, then we might need to move the UPSERT around
-      ** so that it occurs in the correct order. */
-      sAddr.upsertTop = sAddr.upsertTop2 = sqlite3VdbeMakeLabel(v);
-      sAddr.upsertBtm = sqlite3VdbeMakeLabel(v);
+      /* If the constraint-target uniqueness check must be run first.
+      ** Jump to that uniqueness check now */
+      upsertJump = sqlite3VdbeAddOp0(v, OP_Goto);
+      VdbeComment((v, "UPSERT constraint goes first"));
     }
   }
 
@@ -114713,16 +116517,12 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
     ** to defer the running of the rowid conflict checking until after
     ** the UNIQUE constraints have run.
     */
-    assert( OE_Update>OE_Replace );
-    assert( OE_Ignore<OE_Replace );
-    assert( OE_Fail<OE_Replace );
-    assert( OE_Abort<OE_Replace );
-    assert( OE_Rollback<OE_Replace );
-    if( onError>=OE_Replace
-     && (pUpsert || onError!=overrideError)
-     && pTab->pIndex
+    if( onError==OE_Replace      /* IPK rule is REPLACE */
+     && onError!=overrideError   /* Rules for other contraints are different */
+     && pTab->pIndex             /* There exist other constraints */
     ){
-      sAddr.ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1;
+      ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1;
+      VdbeComment((v, "defer IPK REPLACE until last"));
     }
 
     if( isUpdate ){
@@ -114817,9 +116617,9 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
       }
     }
     sqlite3VdbeResolveLabel(v, addrRowidOk);
-    if( sAddr.ipkTop ){
-      sAddr.ipkBtm = sqlite3VdbeAddOp0(v, OP_Goto);
-      sqlite3VdbeJumpHere(v, sAddr.ipkTop-1);
+    if( ipkTop ){
+      ipkBottom = sqlite3VdbeAddOp0(v, OP_Goto);
+      sqlite3VdbeJumpHere(v, ipkTop-1);
     }
   }
 
@@ -114838,18 +116638,18 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
 
     if( aRegIdx[ix]==0 ) continue;  /* Skip indices that do not change */
     if( pUpIdx==pIdx ){
-      addrUniqueOk = sAddr.upsertBtm;
+      addrUniqueOk = upsertJump+1;
       upsertBypass = sqlite3VdbeGoto(v, 0);
       VdbeComment((v, "Skip upsert subroutine"));
-      sqlite3VdbeResolveLabel(v, sAddr.upsertTop2);
+      sqlite3VdbeJumpHere(v, upsertJump);
     }else{
       addrUniqueOk = sqlite3VdbeMakeLabel(v);
     }
-    VdbeNoopComment((v, "uniqueness check for %s", pIdx->zName));
-    if( bAffinityDone==0 ){
+    if( bAffinityDone==0 && (pUpIdx==0 || pUpIdx==pIdx) ){
       sqlite3TableAffinity(v, pTab, regNewData+1);
       bAffinityDone = 1;
     }
+    VdbeNoopComment((v, "uniqueness check for %s", pIdx->zName));
     iThisCur = iIdxCur+ix;
 
 
@@ -114920,15 +116720,6 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
       }
     }
 
-    /* Invoke subroutines to handle IPK replace and upsert prior to running
-    ** the first REPLACE constraint check. */
-    if( onError==OE_Replace ){
-      testcase( sAddr.ipkTop );
-      testcase( sAddr.upsertTop
-             && sqlite3VdbeLabelHasBeenResolved(v,sAddr.upsertTop) );
-      reorderConstraintChecks(v, &sAddr);
-    }
-
     /* 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
@@ -114949,7 +116740,6 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
     }
 
     /* Check to see if the new index entry will be unique */
-    sqlite3ExprCachePush(pParse);
     sqlite3VdbeVerifyAbortable(v, onError);
     sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
                          regIdx, pIdx->nKeyCol); VdbeCoverage(v);
@@ -115051,19 +116841,21 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
       }
     }
     if( pUpIdx==pIdx ){
+      sqlite3VdbeGoto(v, upsertJump+1);
       sqlite3VdbeJumpHere(v, upsertBypass);
     }else{
       sqlite3VdbeResolveLabel(v, addrUniqueOk);
     }
-    sqlite3ExprCachePop(pParse);
     if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);
+  }
 
+  /* If the IPK constraint is a REPLACE, run it last */
+  if( ipkTop ){
+    sqlite3VdbeGoto(v, ipkTop+1);
+    VdbeComment((v, "Do IPK REPLACE"));
+    sqlite3VdbeJumpHere(v, ipkBottom);
   }
-  testcase( sAddr.ipkTop!=0 );
-  testcase( sAddr.upsertTop
-         && sqlite3VdbeLabelHasBeenResolved(v,sAddr.upsertTop) );
-  reorderConstraintChecks(v, &sAddr);
-  
+
   *pbMayReplace = seenReplace;
   VdbeModuleComment((v, "END: GenCnstCks(%d)", seenReplace));
 }
@@ -115159,7 +116951,6 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion(
   sqlite3SetMakeRecordP5(v, pTab);
   if( !bAffinityDone ){
     sqlite3TableAffinity(v, pTab, 0);
-    sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol);
   }
   if( pParse->nested ){
     pik_flags = 0;
@@ -116135,6 +117926,12 @@ struct sqlite3_api_routines {
   int (*str_errcode)(sqlite3_str*);
   int (*str_length)(sqlite3_str*);
   char *(*str_value)(sqlite3_str*);
+  int (*create_window_function)(sqlite3*,const char*,int,int,void*,
+                            void (*xStep)(sqlite3_context*,int,sqlite3_value**),
+                            void (*xFinal)(sqlite3_context*),
+                            void (*xValue)(sqlite3_context*),
+                            void (*xInv)(sqlite3_context*,int,sqlite3_value**),
+                            void(*xDestroy)(void*));
 };
 
 /*
@@ -116420,6 +118217,8 @@ typedef int (*sqlite3_loadext_entry)(
 #define sqlite3_str_errcode            sqlite3_api->str_errcode
 #define sqlite3_str_length             sqlite3_api->str_length
 #define sqlite3_str_value              sqlite3_api->str_value
+/* Version 3.25.0 and later */
+#define sqlite3_create_window_function sqlite3_api->create_window_function
 #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
 
 #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
@@ -116873,7 +118672,9 @@ static const sqlite3_api_routines sqlite3Apis = {
   sqlite3_str_reset,
   sqlite3_str_errcode,
   sqlite3_str_length,
-  sqlite3_str_value
+  sqlite3_str_value,
+  /* Version 3.25.0 and later */
+  sqlite3_create_window_function
 };
 
 /*
@@ -119446,7 +121247,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
 
         if( pTab->tnum<1 ) continue;  /* Skip VIEWs or VIRTUAL TABLEs */
         pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
-        sqlite3ExprCacheClear(pParse);
         sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
                                    1, 0, &iDataCur, &iIdxCur);
         /* reg[7] counts the number of entries in the table.
@@ -119460,6 +121260,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
         assert( sqlite3NoTempsInRange(pParse,1,7+j) );
         sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
         loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
+        if( !isQuick ){
+          /* Sanity check on record header decoding */
+          sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nCol-1, 3);
+          sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
+        }
         /* Verify that all NOT NULL columns really are NOT NULL */
         for(j=0; j<pTab->nCol; j++){
           char *zErr;
@@ -119484,7 +121289,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
             char *zErr;
             int k;
             pParse->iSelfTab = iDataCur + 1;
-            sqlite3ExprCachePush(pParse);
             for(k=pCheck->nExpr-1; k>0; k--){
               sqlite3ExprIfFalse(pParse, pCheck->a[k].pExpr, addrCkFault, 0);
             }
@@ -119497,14 +121301,10 @@ SQLITE_PRIVATE void sqlite3Pragma(
             sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
             integrityCheckResultRow(v);
             sqlite3VdbeResolveLabel(v, addrCkOk);
-            sqlite3ExprCachePop(pParse);
           }
           sqlite3ExprListDelete(db, pCheck);
         }
         if( !isQuick ){ /* Omit the remaining tests for quick_check */
-          /* Sanity check on record header decoding */
-          sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nCol-1, 3);
-          sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
           /* Validate index entries for the current row */
           for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
             int jmp2, jmp3, jmp4, jmp5;
@@ -120119,7 +121919,6 @@ static int pragmaVtabConnect(
   }
   if( i==0 ){
     sqlite3_str_appendf(&acc, "(\"%s\"", pPragma->zName);
-    cSep = ',';
     i++;
   }
   j = 0;
@@ -120412,15 +122211,23 @@ static void corruptSchema(
   const char *zExtra   /* Error information */
 ){
   sqlite3 *db = pData->db;
-  if( !db->mallocFailed && (db->flags & SQLITE_WriteSchema)==0 ){
+  if( db->mallocFailed ){
+    pData->rc = SQLITE_NOMEM_BKPT;
+  }else if( pData->pzErrMsg[0]!=0 ){
+    /* A error message has already been generated.  Do not overwrite it */
+  }else if( pData->mInitFlags & INITFLAG_AlterTable ){
+    *pData->pzErrMsg = sqlite3DbStrDup(db, zExtra);
+    pData->rc = SQLITE_ERROR;
+  }else if( db->flags & SQLITE_WriteSchema ){
+    pData->rc = SQLITE_CORRUPT_BKPT;
+  }else{
     char *z;
     if( zObj==0 ) zObj = "?";
     z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj);
     if( zExtra && zExtra[0] ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra);
-    sqlite3DbFree(db, *pData->pzErrMsg);
     *pData->pzErrMsg = z;
+    pData->rc = SQLITE_CORRUPT_BKPT;
   }
-  pData->rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_CORRUPT_BKPT;
 }
 
 /*
@@ -120472,7 +122279,7 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
     rc = db->errCode;
     assert( (rc&0xFF)==(rcp&0xFF) );
     db->init.iDb = saved_iDb;
-    assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 );
+    /* assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 ); */
     if( SQLITE_OK!=rc ){
       if( db->init.orphanTrigger ){
         assert( iDb==1 );
@@ -120519,7 +122326,7 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
 ** auxiliary databases.  Return one of the SQLITE_ error codes to
 ** indicate success or failure.
 */
-static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
+SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){
   int rc;
   int i;
 #ifndef SQLITE_OMIT_DEPRECATED
@@ -120554,6 +122361,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
   initData.iDb = iDb;
   initData.rc = SQLITE_OK;
   initData.pzErrMsg = pzErrMsg;
+  initData.mInitFlags = mFlags;
   sqlite3InitCallback(&initData, 3, (char **)azArg, 0);
   if( initData.rc ){
     rc = initData.rc;
@@ -120575,7 +122383,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
   ** will be closed before this function returns.  */
   sqlite3BtreeEnter(pDb->pBt);
   if( !sqlite3BtreeIsInReadTrans(pDb->pBt) ){
-    rc = sqlite3BtreeBeginTrans(pDb->pBt, 0);
+    rc = sqlite3BtreeBeginTrans(pDb->pBt, 0, 0);
     if( rc!=SQLITE_OK ){
       sqlite3SetString(pzErrMsg, db, sqlite3ErrStr(rc));
       goto initone_error_out;
@@ -120760,14 +122568,14 @@ SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){
   assert( db->nDb>0 );
   /* Do the main schema first */
   if( !DbHasProperty(db, 0, DB_SchemaLoaded) ){
-    rc = sqlite3InitOne(db, 0, pzErrMsg);
+    rc = sqlite3InitOne(db, 0, pzErrMsg, 0);
     if( rc ) return rc;
   }
   /* All other schemas after the main schema. The "temp" schema must be last */
   for(i=db->nDb-1; i>0; i--){
     assert( i==1 || sqlite3BtreeHoldsMutex(db->aDb[i].pBt) );
     if( !DbHasProperty(db, i, DB_SchemaLoaded) ){
-      rc = sqlite3InitOne(db, i, pzErrMsg);
+      rc = sqlite3InitOne(db, i, pzErrMsg, 0);
       if( rc ) return rc;
     }
   }
@@ -120820,7 +122628,7 @@ static void schemaIsValid(Parse *pParse){
     ** 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);
+      rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
       if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
         sqlite3OomFault(db);
       }
@@ -121317,7 +123125,7 @@ SQLITE_API int sqlite3_prepare16_v3(
 /***/ int sqlite3SelectTrace = 0;
 # define SELECTTRACE(K,P,S,X)  \
   if(sqlite3SelectTrace&(K))   \
-    sqlite3DebugPrintf("%s/%d/%p: ",(S)->zSelName,(P)->addrExplain,(S)),\
+    sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\
     sqlite3DebugPrintf X
 #else
 # define SELECTTRACE(K,P,S,X)
@@ -121364,8 +123172,8 @@ struct SortCtx {
   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 */
+  int labelOBLopt;      /* Jump here when sorter is full */
   u8 sortFlags;         /* Zero or more SORTFLAG_* bits */
-  u8 bOrderedInnerLoop; /* ORDER BY correctly sorts the inner loop */
 #ifdef SQLITE_ENABLE_SORTER_REFERENCES
   u8 nDefer;            /* Number of valid entries in aDefer[] */
   struct DeferredCsr {
@@ -121392,6 +123200,11 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
     sqlite3ExprDelete(db, p->pHaving);
     sqlite3ExprListDelete(db, p->pOrderBy);
     sqlite3ExprDelete(db, p->pLimit);
+#ifndef SQLITE_OMIT_WINDOWFUNC
+    if( OK_IF_ALWAYS_TRUE(p->pWinDefn) ){
+      sqlite3WindowListDelete(db, p->pWinDefn);
+    }
+#endif
     if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith);
     if( bFree ) sqlite3DbFreeNN(db, p);
     p = pPrior;
@@ -121442,9 +123255,7 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(
   pNew->selFlags = selFlags;
   pNew->iLimit = 0;
   pNew->iOffset = 0;
-#if SELECTTRACE_ENABLED
-  pNew->zSelName[0] = 0;
-#endif
+  pNew->selId = ++pParse->nSelect;
   pNew->addrOpenEphm[0] = -1;
   pNew->addrOpenEphm[1] = -1;
   pNew->nSelectRow = 0;
@@ -121458,6 +123269,10 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(
   pNew->pNext = 0;
   pNew->pLimit = pLimit;
   pNew->pWith = 0;
+#ifndef SQLITE_OMIT_WINDOWFUNC
+  pNew->pWin = 0;
+  pNew->pWinDefn = 0;
+#endif
   if( pParse->db->mallocFailed ) {
     clearSelect(pParse->db, pNew, pNew!=&standin);
     pNew = 0;
@@ -121468,17 +123283,6 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(
   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.
@@ -121825,14 +123629,6 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
   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 */
-);
-
 /*
 ** An instance of this object holds information (beyond pParse and pSelect)
 ** needed to load the next result row that is to be added to the sorter.
@@ -121974,7 +123770,7 @@ static void pushOntoSorter(
     memset(pKI->aSortOrder, 0, pKI->nKeyField); /* Makes OP_Jump testable */
     sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO);
     testcase( pKI->nAllField > pKI->nKeyField+2 );
-    pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat,
+    pOp->p4.pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pSort->pOrderBy,nOBSat,
                                            pKI->nAllField-pKI->nKeyField-1);
     addrJmp = sqlite3VdbeCurrentAddr(v);
     sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
@@ -122001,10 +123797,10 @@ static void pushOntoSorter(
     ** than LIMIT+OFFSET items in the sorter.
     **
     ** If the new record does not need to be inserted into the sorter,
-    ** jump to the next iteration of the loop. Or, if the
-    ** pSort->bOrderedInnerLoop flag is set to indicate that the inner
-    ** loop delivers items in sorted order, jump to the next iteration
-    ** of the outer loop.
+    ** jump to the next iteration of the loop. If the pSort->labelOBLopt
+    ** value is not zero, then it is a label of where to jump.  Otherwise,
+    ** just bypass the row insert logic.  See the header comment on the
+    ** sqlite3WhereOrderByLimitOptLabel() function for additional info.
     */
     int iCsr = pSort->iECursor;
     sqlite3VdbeAddOp2(v, OP_IfNotZero, iLimit, sqlite3VdbeCurrentAddr(v)+4);
@@ -122026,9 +123822,8 @@ static void pushOntoSorter(
   sqlite3VdbeAddOp4Int(v, op, pSort->iECursor, regRecord,
                        regBase+nOBSat, nBase-nOBSat);
   if( iSkip ){
-    assert( pSort->bOrderedInnerLoop==0 || pSort->bOrderedInnerLoop==1 );
     sqlite3VdbeChangeP2(v, iSkip,
-         sqlite3VdbeCurrentAddr(v) + pSort->bOrderedInnerLoop);
+         pSort->labelOBLopt ? pSort->labelOBLopt : sqlite3VdbeCurrentAddr(v));
   }
 }
 
@@ -122457,7 +124252,6 @@ static void selectInnerLoop(
         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);
       }
@@ -122501,7 +124295,6 @@ static void selectInnerLoop(
         sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
       }else{
         sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nResultCol);
-        sqlite3ExprCacheAffinityChange(pParse, regResult, nResultCol);
       }
       break;
     }
@@ -122644,7 +124437,7 @@ SQLITE_PRIVATE int sqlite3KeyInfoIsWriteable(KeyInfo *p){ return p->nRef==1; }
 ** function is responsible for seeing that this structure is eventually
 ** freed.
 */
-static KeyInfo *keyInfoFromExprList(
+SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoFromExprList(
   Parse *pParse,       /* Parsing context */
   ExprList *pList,     /* Form the KeyInfo object from this ExprList */
   int iStart,          /* Begin with this column of pList */
@@ -122858,7 +124651,6 @@ static void generateSortTail(
       assert( nColumn==sqlite3Strlen30(pDest->zAffSdst) );
       sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, nColumn, regRowid,
                         pDest->zAffSdst, nColumn);
-      sqlite3ExprCacheAffinityChange(pParse, regRow, nColumn);
       sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, regRowid, regRow, nColumn);
       break;
     }
@@ -122873,7 +124665,6 @@ static void generateSortTail(
       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);
       }
@@ -123474,7 +125265,6 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
   ** The current implementation interprets "LIMIT 0" to mean
   ** no rows.
   */
-  sqlite3ExprCacheClear(pParse);
   if( pLimit ){
     assert( pLimit->op==TK_LIMIT );
     assert( pLimit->pLeft!=0 );
@@ -124260,7 +126050,6 @@ static int generateOutputSubroutine(
       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);
@@ -124303,7 +126092,6 @@ static int generateOutputSubroutine(
     default: {
       assert( pDest->eDest==SRT_Output );
       sqlite3VdbeAddOp2(v, OP_ResultRow, pIn->iSdst, pIn->nSdst);
-      sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, pIn->nSdst);
       break;
     }
   }
@@ -124758,7 +126546,7 @@ static Expr *substExpr(
       Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr;
       Expr ifNullRow;
       assert( pSubst->pEList!=0 && pExpr->iColumn<pSubst->pEList->nExpr );
-      assert( pExpr->pLeft==0 && pExpr->pRight==0 );
+      assert( pExpr->pRight==0 );
       if( sqlite3ExprIsVector(pCopy) ){
         sqlite3VectorErrorMsg(pSubst->pParse, pCopy);
       }else{
@@ -124972,6 +126760,10 @@ static void substSelect(
 **        "SELECT x FROM (SELECT max(y), x FROM t1)" would not necessarily
 **        return the value X for which Y was maximal.)
 **
+**  (25)  If either the subquery or the parent query contains a window
+**        function in the select list or ORDER BY clause, flattening
+**        is not attempted.
+**
 **
 ** 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
@@ -125015,6 +126807,10 @@ static int flattenSubquery(
   pSub = pSubitem->pSelect;
   assert( pSub!=0 );
 
+#ifndef SQLITE_OMIT_WINDOWFUNC
+  if( p->pWin || pSub->pWin ) return 0;                  /* Restriction (25) */
+#endif
+
   pSubSrc = pSub->pSrc;
   assert( pSubSrc );
   /* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants,
@@ -125125,8 +126921,8 @@ static int flattenSubquery(
   assert( (p->selFlags & SF_Recursive)==0 || pSub->pPrior==0 );
 
   /***** If we reach this point, flattening is permitted. *****/
-  SELECTTRACE(1,pParse,p,("flatten %s.%p from term %d\n",
-                   pSub->zSelName, pSub, iFrom));
+  SELECTTRACE(1,pParse,p,("flatten %u.%p from term %d\n",
+                   pSub->selId, pSub, iFrom));
 
   /* Authorize the subquery */
   pParse->zAuthContext = pSubitem->zName;
@@ -125177,7 +126973,6 @@ static int flattenSubquery(
     p->pPrior = 0;
     p->pLimit = 0;
     pNew = sqlite3SelectDup(db, p, 0);
-    sqlite3SelectSetName(pNew, pSub->zSelName);
     p->pLimit = pLimit;
     p->pOrderBy = pOrderBy;
     p->pSrc = pSrc;
@@ -125190,7 +126985,7 @@ static int flattenSubquery(
       pNew->pNext = p;
       p->pPrior = pNew;
       SELECTTRACE(2,pParse,p,("compound-subquery flattener"
-                              " creates %s.%p as peer\n",pNew->zSelName, pNew));
+                              " creates %u as peer\n",pNew->selId));
     }
     if( db->mallocFailed ) return 1;
   }
@@ -125375,7 +127170,168 @@ static int flattenSubquery(
 }
 #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
 
+/*
+** A structure to keep track of all of the column values that fixed to
+** a known value due to WHERE clause constraints of the form COLUMN=VALUE.
+*/
+typedef struct WhereConst WhereConst;
+struct WhereConst {
+  Parse *pParse;   /* Parsing context */
+  int nConst;      /* Number for COLUMN=CONSTANT terms */
+  int nChng;       /* Number of times a constant is propagated */
+  Expr **apExpr;   /* [i*2] is COLUMN and [i*2+1] is VALUE */
+};
+
+/*
+** Add a new entry to the pConst object
+*/
+static void constInsert(
+  WhereConst *pConst,
+  Expr *pColumn,
+  Expr *pValue
+){
+
+  pConst->nConst++;
+  pConst->apExpr = sqlite3DbReallocOrFree(pConst->pParse->db, pConst->apExpr,
+                         pConst->nConst*2*sizeof(Expr*));
+  if( pConst->apExpr==0 ){
+    pConst->nConst = 0;
+  }else{
+    if( ExprHasProperty(pValue, EP_FixedCol) ) pValue = pValue->pLeft;
+    pConst->apExpr[pConst->nConst*2-2] = pColumn;
+    pConst->apExpr[pConst->nConst*2-1] = pValue;
+  }
+}
+
+/*
+** Find all terms of COLUMN=VALUE or VALUE=COLUMN in pExpr where VALUE
+** is a constant expression and where the term must be true because it
+** is part of the AND-connected terms of the expression.  For each term
+** found, add it to the pConst structure.
+*/
+static void findConstInWhere(WhereConst *pConst, Expr *pExpr){
+  Expr *pRight, *pLeft;
+  if( pExpr==0 ) return;
+  if( ExprHasProperty(pExpr, EP_FromJoin) ) return;
+  if( pExpr->op==TK_AND ){
+    findConstInWhere(pConst, pExpr->pRight);
+    findConstInWhere(pConst, pExpr->pLeft);
+    return;
+  }
+  if( pExpr->op!=TK_EQ ) return;
+  pRight = pExpr->pRight;
+  pLeft = pExpr->pLeft;
+  assert( pRight!=0 );
+  assert( pLeft!=0 );
+  if( pRight->op==TK_COLUMN
+   && !ExprHasProperty(pRight, EP_FixedCol)
+   && sqlite3ExprIsConstant(pLeft)
+   && sqlite3IsBinary(sqlite3BinaryCompareCollSeq(pConst->pParse,pLeft,pRight))
+  ){
+    constInsert(pConst, pRight, pLeft);
+  }else
+  if( pLeft->op==TK_COLUMN
+   && !ExprHasProperty(pLeft, EP_FixedCol)
+   && sqlite3ExprIsConstant(pRight)
+   && sqlite3IsBinary(sqlite3BinaryCompareCollSeq(pConst->pParse,pLeft,pRight))
+  ){
+    constInsert(pConst, pLeft, pRight);
+  }
+}
+
+/*
+** This is a Walker expression callback.  pExpr is a candidate expression
+** to be replaced by a value.  If pExpr is equivalent to one of the
+** columns named in pWalker->u.pConst, then overwrite it with its
+** corresponding value.
+*/
+static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){
+  int i;
+  WhereConst *pConst;
+  if( pExpr->op!=TK_COLUMN ) return WRC_Continue;
+  if( ExprHasProperty(pExpr, EP_FixedCol) ) return WRC_Continue;
+  pConst = pWalker->u.pConst;
+  for(i=0; i<pConst->nConst; i++){
+    Expr *pColumn = pConst->apExpr[i*2];
+    if( pColumn==pExpr ) continue;
+    if( pColumn->iTable!=pExpr->iTable ) continue;
+    if( pColumn->iColumn!=pExpr->iColumn ) continue;
+    /* A match is found.  Add the EP_FixedCol property */
+    pConst->nChng++;
+    ExprClearProperty(pExpr, EP_Leaf);
+    ExprSetProperty(pExpr, EP_FixedCol);
+    assert( pExpr->pLeft==0 );
+    pExpr->pLeft = sqlite3ExprDup(pConst->pParse->db, pConst->apExpr[i*2+1], 0);
+    break;
+  }
+  return WRC_Prune;
+}
 
+/*
+** The WHERE-clause constant propagation optimization.
+**
+** If the WHERE clause contains terms of the form COLUMN=CONSTANT or
+** CONSTANT=COLUMN that must be tree (in other words, if the terms top-level
+** AND-connected terms that are not part of a ON clause from a LEFT JOIN)
+** then throughout the query replace all other occurrences of COLUMN
+** with CONSTANT within the WHERE clause.
+**
+** For example, the query:
+**
+**      SELECT * FROM t1, t2, t3 WHERE t1.a=39 AND t2.b=t1.a AND t3.c=t2.b
+**
+** Is transformed into
+**
+**      SELECT * FROM t1, t2, t3 WHERE t1.a=39 AND t2.b=39 AND t3.c=39
+**
+** Return true if any transformations where made and false if not.
+**
+** Implementation note:  Constant propagation is tricky due to affinity
+** and collating sequence interactions.  Consider this example:
+**
+**    CREATE TABLE t1(a INT,b TEXT);
+**    INSERT INTO t1 VALUES(123,'0123');
+**    SELECT * FROM t1 WHERE a=123 AND b=a;
+**    SELECT * FROM t1 WHERE a=123 AND b=123;
+**
+** The two SELECT statements above should return different answers.  b=a
+** is alway true because the comparison uses numeric affinity, but b=123
+** is false because it uses text affinity and '0123' is not the same as '123'.
+** To work around this, the expression tree is not actually changed from
+** "b=a" to "b=123" but rather the "a" in "b=a" is tagged with EP_FixedCol
+** and the "123" value is hung off of the pLeft pointer.  Code generator
+** routines know to generate the constant "123" instead of looking up the
+** column value.  Also, to avoid collation problems, this optimization is
+** only attempted if the "a=123" term uses the default BINARY collation.
+*/
+static int propagateConstants(
+  Parse *pParse,   /* The parsing context */
+  Select *p        /* The query in which to propagate constants */
+){
+  WhereConst x;
+  Walker w;
+  int nChng = 0;
+  x.pParse = pParse;
+  do{
+    x.nConst = 0;
+    x.nChng = 0;
+    x.apExpr = 0;
+    findConstInWhere(&x, p->pWhere);
+    if( x.nConst ){
+      memset(&w, 0, sizeof(w));
+      w.pParse = pParse;
+      w.xExprCallback = propagateConstantExprRewrite;
+      w.xSelectCallback = sqlite3SelectWalkNoop;
+      w.xSelectCallback2 = 0;
+      w.walkerDepth = 0;
+      w.u.pConst = &x;
+      sqlite3WalkExpr(&w, p->pWhere);
+      sqlite3DbFree(x.pParse->db, x.apExpr);
+      nChng += x.nChng;
+    }
+  }while( x.nChng );  
+  return nChng;
+}
 
 #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
 /*
@@ -125405,7 +127361,7 @@ static int flattenSubquery(
 **   (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).
+**       clause would change the meaning of the LIMIT).
 **
 **   (4) The inner query is the right operand of a LEFT JOIN and the
 **       expression to be pushed down does not come from the ON clause
@@ -125424,6 +127380,10 @@ static int flattenSubquery(
 **       But if the (b2=2) term were to be pushed down into the bb subquery,
 **       then the (1,1,NULL) row would be suppressed.
 **
+**   (6) The inner query features one or more window-functions (since 
+**       changes to the WHERE clause of the inner query could change the 
+**       window over which window functions are calculated).
+**
 ** Return 0 if no changes are made and non-zero if one or more WHERE clause
 ** terms are duplicated into the subquery.
 */
@@ -125439,6 +127399,10 @@ static int pushDownWhereTerms(
   if( pWhere==0 ) return 0;
   if( pSubq->selFlags & SF_Recursive ) return 0;  /* restriction (2) */
 
+#ifndef SQLITE_OMIT_WINDOWFUNC
+  if( pSubq->pWin ) return 0;    /* restriction (6) */
+#endif
+
 #ifdef SQLITE_DEBUG
   /* Only the first term of a compound can have a WITH clause.  But make
   ** sure no other terms are marked SF_Recursive in case something changes
@@ -125884,6 +127848,35 @@ static void selectPopWith(Walker *pWalker, Select *p){
 #define selectPopWith 0
 #endif
 
+/*
+** The SrcList_item structure passed as the second argument represents a
+** sub-query in the FROM clause of a SELECT statement. This function
+** allocates and populates the SrcList_item.pTab object. If successful,
+** SQLITE_OK is returned. Otherwise, if an OOM error is encountered,
+** SQLITE_NOMEM.
+*/
+SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, struct SrcList_item *pFrom){
+  Select *pSel = pFrom->pSelect;
+  Table *pTab;
+
+  assert( pSel );
+  pFrom->pTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table));
+  if( pTab==0 ) return SQLITE_NOMEM;
+  pTab->nTabRef = 1;
+  if( pFrom->zAlias ){
+    pTab->zName = sqlite3DbStrDup(pParse->db, pFrom->zAlias);
+  }else{
+    pTab->zName = sqlite3MPrintf(pParse->db, "subquery_%u", pSel->selId);
+  }
+  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;
+
+  return SQLITE_OK;
+}
+
 /*
 ** This routine is a Walker callback for "expanding" a SELECT statement.
 ** "Expanding" means to do the following:
@@ -125956,19 +127949,7 @@ static int selectExpander(Walker *pWalker, Select *p){
       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;
-      if( pFrom->zAlias ){
-        pTab->zName = sqlite3DbStrDup(db, pFrom->zAlias);
-      }else{
-        pTab->zName = sqlite3MPrintf(db, "subquery_%p", (void*)pTab);
-      }
-      while( pSel->pPrior ){ pSel = pSel->pPrior; }
-      sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol);
-      pTab->iPKey = -1;
-      pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
-      pTab->tabFlags |= TF_Ephemeral;
+      if( sqlite3ExpandSubquery(pParse, pFrom) ) return WRC_Abort;
 #endif
     }else{
       /* An ordinary table or view name in the FROM clause */
@@ -125991,7 +127972,6 @@ static int selectExpander(Walker *pWalker, Select *p){
         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);
@@ -126269,7 +128249,7 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
   struct SrcList_item *pFrom;
 
   assert( p->selFlags & SF_Resolved );
-  assert( (p->selFlags & SF_HasTypeInfo)==0 );
+  if( p->selFlags & SF_HasTypeInfo ) return;
   p->selFlags |= SF_HasTypeInfo;
   pParse = pWalker->pParse;
   pTabList = p->pSrc;
@@ -126372,7 +128352,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
            "argument");
         pFunc->iDistinct = -1;
       }else{
-        KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0, 0);
+        KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pE->x.pList,0,0);
         sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0,
                           (char*)pKeyInfo, P4_KEYINFO);
       }
@@ -126396,11 +128376,17 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
   }
 }
 
+
 /*
 ** Update the accumulator memory cells for an aggregate based on
 ** the current cursor position.
+**
+** If regAcc is non-zero and there are no min() or max() aggregates
+** in pAggInfo, then only populate the pAggInfo->nAccumulator accumulator
+** registers i register regAcc contains 0. The caller will take care
+** of setting and clearing regAcc.
 */
-static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
+static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
   Vdbe *v = pParse->pVdbe;
   int i;
   int regHit = 0;
@@ -126443,36 +128429,24 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
       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);
+    sqlite3VdbeAddOp3(v, OP_AggStep, 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==0 && pAggInfo->nAccumulator ){
+    regHit = regAcc;
+  }
   if( regHit ){
     addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v);
   }
-  sqlite3ExprCacheClear(pParse);
   for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
     sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
   }
   pAggInfo->directMode = 0;
-  sqlite3ExprCacheClear(pParse);
   if( addrHitTest ){
     sqlite3VdbeJumpHere(v, addrHitTest);
   }
@@ -126602,6 +128576,7 @@ static struct SrcList_item *isSelfJoinView(
 ** The transformation only works if all of the following are true:
 **
 **   *  The subquery is a UNION ALL of two or more terms
+**   *  The subquery does not have a LIMIT clause
 **   *  There is no WHERE or GROUP BY or HAVING clauses on the subqueries
 **   *  The outer query is a simple count(*)
 **
@@ -126625,6 +128600,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
   do{
     if( pSub->op!=TK_ALL && pSub->pPrior ) return 0;  /* Must be UNION ALL */
     if( pSub->pWhere ) return 0;                      /* No WHERE clause */
+    if( pSub->pLimit ) return 0;                      /* No LIMIT clause */
     if( pSub->selFlags & SF_Aggregate ) return 0;     /* Not an aggregate */
     pSub = pSub->pPrior;                              /* Repeat over compound */
   }while( pSub );
@@ -126737,14 +128713,10 @@ SQLITE_PRIVATE int sqlite3Select(
     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 & 0x104 ){
     SELECTTRACE(0x104,pParse,p, ("after name resolution:\n"));
@@ -126756,6 +128728,22 @@ SQLITE_PRIVATE int sqlite3Select(
     generateColumnNames(pParse, p);
   }
 
+#ifndef SQLITE_OMIT_WINDOWFUNC
+  if( sqlite3WindowRewrite(pParse, p) ){
+    goto select_end;
+  }
+#if SELECTTRACE_ENABLED
+  if( sqlite3SelectTrace & 0x108 ){
+    SELECTTRACE(0x104,pParse,p, ("after window rewrite:\n"));
+    sqlite3TreeViewSelect(0, p, 0);
+  }
+#endif
+#endif /* SQLITE_OMIT_WINDOWFUNC */
+  pTabList = p->pSrc;
+  isAgg = (p->selFlags & SF_Aggregate)!=0;
+  memset(&sSort, 0, sizeof(sSort));
+  sSort.pOrderBy = p->pOrderBy;
+
   /* Try to various optimizations (flattening subqueries, and strength
   ** reduction of join operators) in the FROM clause up into the main query
   */
@@ -126855,6 +128843,35 @@ SQLITE_PRIVATE int sqlite3Select(
   }
 #endif
 
+  /* Do the WHERE-clause constant propagation optimization if this is
+  ** a join.  No need to speed time on this operation for non-join queries
+  ** as the equivalent optimization will be handled by query planner in
+  ** sqlite3WhereBegin().
+  */
+  if( pTabList->nSrc>1
+   && OptimizationEnabled(db, SQLITE_PropagateConst)
+   && propagateConstants(pParse, p)
+  ){
+#if SELECTTRACE_ENABLED
+    if( sqlite3SelectTrace & 0x100 ){
+      SELECTTRACE(0x100,pParse,p,("After constant propagation:\n"));
+      sqlite3TreeViewSelect(0, p, 0);
+    }
+#endif
+  }else{
+    SELECTTRACE(0x100,pParse,p,("Constant propagation not helpful\n"));
+  }
+
+#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
+  if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView)
+   && countOfViewOptimization(pParse, p)
+  ){
+    if( db->mallocFailed ) goto select_end;
+    pEList = p->pEList;
+    pTabList = p->pSrc;
+  }
+#endif
+
   /* For each term in the FROM clause, do two things:
   ** (1) Authorized unreferenced tables
   ** (2) Generate code for all sub-queries
@@ -126928,7 +128945,8 @@ SQLITE_PRIVATE int sqlite3Select(
     ){
 #if SELECTTRACE_ENABLED
       if( sqlite3SelectTrace & 0x100 ){
-        SELECTTRACE(0x100,pParse,p,("After WHERE-clause push-down:\n"));
+        SELECTTRACE(0x100,pParse,p,
+            ("After WHERE-clause push-down into subquery %d:\n", pSub->selId));
         sqlite3TreeViewSelect(0, p, 0);
       }
 #endif
@@ -126962,7 +128980,7 @@ SQLITE_PRIVATE int sqlite3Select(
       VdbeComment((v, "%s", pItem->pTab->zName));
       pItem->addrFillSub = addrTop;
       sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
-      ExplainQueryPlan((pParse, 1, "CO-ROUTINE 0x%p", pSub));
+      ExplainQueryPlan((pParse, 1, "CO-ROUTINE %u", pSub->selId));
       sqlite3Select(pParse, pSub, &dest);
       pItem->pTab->nRowLogEst = pSub->nSelectRow;
       pItem->fg.viaCoroutine = 1;
@@ -127001,7 +129019,7 @@ SQLITE_PRIVATE int sqlite3Select(
         pSub->nSelectRow = pPrior->pSelect->nSelectRow;
       }else{
         sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
-        ExplainQueryPlan((pParse, 1, "MATERIALIZE 0x%p", pSub));
+        ExplainQueryPlan((pParse, 1, "MATERIALIZE %u", pSub->selId));
         sqlite3Select(pParse, pSub, &dest);
       }
       pItem->pTab->nRowLogEst = pSub->nSelectRow;
@@ -127032,16 +129050,6 @@ SQLITE_PRIVATE int sqlite3Select(
   }
 #endif
 
-#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
-  if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView)
-   && countOfViewOptimization(pParse, p)
-  ){
-    if( db->mallocFailed ) goto select_end;
-    pEList = p->pEList;
-    pTabList = p->pSrc;
-  }
-#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:
@@ -127085,7 +129093,8 @@ SQLITE_PRIVATE int sqlite3Select(
   */
   if( sSort.pOrderBy ){
     KeyInfo *pKeyInfo;
-    pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, pEList->nExpr);
+    pKeyInfo = sqlite3KeyInfoFromExprList(
+        pParse, sSort.pOrderBy, 0, pEList->nExpr);
     sSort.iECursor = pParse->nTab++;
     sSort.addrSortIndex =
       sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
@@ -127119,9 +129128,9 @@ SQLITE_PRIVATE int sqlite3Select(
   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);
+                       sDistinct.tabTnct, 0, 0,
+                       (char*)sqlite3KeyInfoFromExprList(pParse, p->pEList,0,0),
+                       P4_KEYINFO);
     sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
     sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED;
   }else{
@@ -127130,9 +129139,16 @@ SQLITE_PRIVATE int sqlite3Select(
 
   if( !isAgg && pGroupBy==0 ){
     /* No aggregate functions and no GROUP BY clause */
-    u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0);
+    u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0)
+                   | (p->selFlags & SF_FixedLimit);
+#ifndef SQLITE_OMIT_WINDOWFUNC
+    Window *pWin = p->pWin;      /* Master window object (or NULL) */
+    if( pWin ){
+      sqlite3WindowCodeInit(pParse, pWin);
+    }
+#endif
     assert( WHERE_USE_LIMIT==SF_FixedLimit );
-    wctrlFlags |= p->selFlags & SF_FixedLimit;
+
 
     /* Begin the database scan. */
     SELECTTRACE(1,pParse,p,("WhereBegin\n"));
@@ -127147,7 +129163,7 @@ SQLITE_PRIVATE int sqlite3Select(
     }
     if( sSort.pOrderBy ){
       sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo);
-      sSort.bOrderedInnerLoop = sqlite3WhereOrderedInnerLoop(pWInfo);
+      sSort.labelOBLopt = sqlite3WhereOrderByLimitOptLabel(pWInfo);
       if( sSort.nOBSat==sSort.pOrderBy->nExpr ){
         sSort.pOrderBy = 0;
       }
@@ -127161,15 +129177,37 @@ SQLITE_PRIVATE int sqlite3Select(
       sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex);
     }
 
-    /* Use the standard inner loop. */
     assert( p->pEList==pEList );
-    selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest,
-                    sqlite3WhereContinueLabel(pWInfo),
-                    sqlite3WhereBreakLabel(pWInfo));
+#ifndef SQLITE_OMIT_WINDOWFUNC
+    if( pWin ){
+      int addrGosub = sqlite3VdbeMakeLabel(v);
+      int iCont = sqlite3VdbeMakeLabel(v);
+      int iBreak = sqlite3VdbeMakeLabel(v);
+      int regGosub = ++pParse->nMem;
+
+      sqlite3WindowCodeStep(pParse, p, pWInfo, regGosub, addrGosub);
+
+      sqlite3VdbeAddOp2(v, OP_Goto, 0, iBreak);
+      sqlite3VdbeResolveLabel(v, addrGosub);
+      VdbeNoopComment((v, "inner-loop subroutine"));
+      sSort.labelOBLopt = 0;
+      selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, iCont, iBreak);
+      sqlite3VdbeResolveLabel(v, iCont);
+      sqlite3VdbeAddOp1(v, OP_Return, regGosub);
+      VdbeComment((v, "end inner-loop subroutine"));
+      sqlite3VdbeResolveLabel(v, iBreak);
+    }else
+#endif /* SQLITE_OMIT_WINDOWFUNC */
+    {
+      /* Use the standard inner loop. */
+      selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest,
+          sqlite3WhereContinueLabel(pWInfo),
+          sqlite3WhereBreakLabel(pWInfo));
 
-    /* End the database scan loop.
-    */
-    sqlite3WhereEnd(pWInfo);
+      /* End the database scan loop.
+      */
+      sqlite3WhereEnd(pWInfo);
+    }
   }else{
     /* This case when there exist aggregate functions or a GROUP BY clause
     ** or both */
@@ -127298,7 +129336,7 @@ SQLITE_PRIVATE int sqlite3Select(
       ** will be converted into a Noop.  
       */
       sAggInfo.sortingIdx = pParse->nTab++;
-      pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, sAggInfo.nColumn);
+      pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pGroupBy,0,sAggInfo.nColumn);
       addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen, 
           sAggInfo.sortingIdx, sAggInfo.nSortingColumn, 
           0, (char*)pKeyInfo, P4_KEYINFO);
@@ -127317,8 +129355,6 @@ SQLITE_PRIVATE int sqlite3Select(
       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.
@@ -127364,15 +129400,14 @@ SQLITE_PRIVATE int sqlite3Select(
           }
         }
         regBase = sqlite3GetTempRange(pParse, nCol);
-        sqlite3ExprCacheClear(pParse);
         sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0);
         j = nGroupBy;
         for(i=0; i<sAggInfo.nColumn; i++){
           struct AggInfo_col *pCol = &sAggInfo.aCol[i];
           if( pCol->iSorterColumn>=j ){
             int r1 = j + regBase;
-            sqlite3ExprCodeGetColumnToReg(pParse, 
-                               pCol->pTab, pCol->iColumn, pCol->iTable, r1);
+            sqlite3ExprCodeGetColumnOfTable(v,
+                               pCol->pTab, pCol->iTable, pCol->iColumn, r1);
             j++;
           }
         }
@@ -127388,8 +129423,6 @@ SQLITE_PRIVATE int sqlite3Select(
         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
@@ -127412,7 +129445,6 @@ SQLITE_PRIVATE int sqlite3Select(
       ** 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);
@@ -127451,7 +129483,7 @@ SQLITE_PRIVATE int sqlite3Select(
       ** the current row
       */
       sqlite3VdbeJumpHere(v, addr1);
-      updateAccumulator(pParse, &sAggInfo);
+      updateAccumulator(pParse, iUseFlag, &sAggInfo);
       sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag);
       VdbeComment((v, "indicate data in accumulator"));
 
@@ -127503,6 +129535,8 @@ SQLITE_PRIVATE int sqlite3Select(
       */
       sqlite3VdbeResolveLabel(v, addrReset);
       resetAccumulator(pParse, &sAggInfo);
+      sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag);
+      VdbeComment((v, "indicate accumulator empty"));
       sqlite3VdbeAddOp1(v, OP_Return, regReset);
      
     } /* endif pGroupBy.  Begin aggregate queries without GROUP BY: */
@@ -127568,6 +129602,23 @@ SQLITE_PRIVATE int sqlite3Select(
       }else
 #endif /* SQLITE_OMIT_BTREECOUNT */
       {
+        int regAcc = 0;           /* "populate accumulators" flag */
+
+        /* If there are accumulator registers but no min() or max() functions,
+        ** allocate register regAcc. Register regAcc will contain 0 the first
+        ** time the inner loop runs, and 1 thereafter. The code generated
+        ** by updateAccumulator() only updates the accumulator registers if
+        ** regAcc contains 0.  */
+        if( sAggInfo.nAccumulator ){
+          for(i=0; i<sAggInfo.nFunc; i++){
+            if( sAggInfo.aFunc[i].pFunc->funcFlags&SQLITE_FUNC_NEEDCOLL ) break;
+          }
+          if( i==sAggInfo.nFunc ){
+            regAcc = ++pParse->nMem;
+            sqlite3VdbeAddOp2(v, OP_Integer, 0, regAcc);
+          }
+        }
+
         /* 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.
@@ -127589,7 +129640,8 @@ SQLITE_PRIVATE int sqlite3Select(
         if( pWInfo==0 ){
           goto select_end;
         }
-        updateAccumulator(pParse, &sAggInfo);
+        updateAccumulator(pParse, regAcc, &sAggInfo);
+        if( regAcc ) sqlite3VdbeAddOp2(v, OP_Integer, 1, regAcc);
         if( sqlite3WhereIsOrdered(pWInfo)>0 ){
           sqlite3VdbeGoto(v, sqlite3WhereBreakLabel(pWInfo));
           VdbeComment((v, "%s() by index",
@@ -128033,14 +130085,16 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
     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);
+  if( !IN_RENAME_OBJECT ){
+    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;
     }
-    goto trigger_cleanup;
   }
 
   /* Do not create a trigger on a system table */
@@ -128064,7 +130118,7 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
   }
 
 #ifndef SQLITE_OMIT_AUTHORIZATION
-  {
+  if( !IN_RENAME_OBJECT ){
     int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
     int code = SQLITE_CREATE_TRIGGER;
     const char *zDb = db->aDb[iTabDb].zDbSName;
@@ -128098,8 +130152,15 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
   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);
+  if( IN_RENAME_OBJECT ){
+    sqlite3RenameTokenRemap(pParse, pTrigger->table, pTableName->a[0].zName);
+    pTrigger->pWhen = pWhen;
+    pWhen = 0;
+  }else{
+    pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE);
+  }
+  pTrigger->pColumns = pColumns;
+  pColumns = 0;
   assert( pParse->pNewTrigger==0 );
   pParse->pNewTrigger = pTrigger;
 
@@ -128148,6 +130209,14 @@ SQLITE_PRIVATE void sqlite3FinishTrigger(
     goto triggerfinish_cleanup;
   }
 
+#ifndef SQLITE_OMIT_ALTERTABLE
+  if( IN_RENAME_OBJECT ){
+    assert( !db->init.busy );
+    pParse->pNewTrigger = pTrig;
+    pTrig = 0;
+  }else
+#endif
+
   /* if we are not initializing,
   ** build the sqlite_master entry
   */
@@ -128189,7 +130258,7 @@ SQLITE_PRIVATE void sqlite3FinishTrigger(
 
 triggerfinish_cleanup:
   sqlite3DeleteTrigger(db, pTrig);
-  assert( !pParse->pNewTrigger );
+  assert( IN_RENAME_OBJECT || !pParse->pNewTrigger );
   sqlite3DeleteTriggerStep(db, pStepList);
 }
 
@@ -128236,12 +130305,13 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(
 ** If an OOM error occurs, NULL is returned and db->mallocFailed is set.
 */
 static TriggerStep *triggerStepAllocate(
-  sqlite3 *db,                /* Database connection */
+  Parse *pParse,              /* Parser context */
   u8 op,                      /* Trigger opcode */
   Token *pName,               /* The target name */
   const char *zStart,         /* Start of SQL text */
   const char *zEnd            /* End of SQL text */
 ){
+  sqlite3 *db = pParse->db;
   TriggerStep *pTriggerStep;
 
   pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n + 1);
@@ -128252,6 +130322,9 @@ static TriggerStep *triggerStepAllocate(
     pTriggerStep->zTarget = z;
     pTriggerStep->op = op;
     pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd);
+    if( IN_RENAME_OBJECT ){
+      sqlite3RenameTokenMap(pParse, pTriggerStep->zTarget, pName);
+    }
   }
   return pTriggerStep;
 }
@@ -128264,7 +130337,7 @@ static TriggerStep *triggerStepAllocate(
 ** body of a trigger.
 */
 SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(
-  sqlite3 *db,        /* The database connection */
+  Parse *pParse,      /* Parser */
   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 */
@@ -128273,13 +130346,19 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(
   const char *zStart, /* Start of SQL text */
   const char *zEnd    /* End of SQL text */
 ){
+  sqlite3 *db = pParse->db;
   TriggerStep *pTriggerStep;
 
   assert(pSelect != 0 || db->mallocFailed);
 
-  pTriggerStep = triggerStepAllocate(db, TK_INSERT, pTableName, zStart, zEnd);
+  pTriggerStep = triggerStepAllocate(pParse, TK_INSERT, pTableName,zStart,zEnd);
   if( pTriggerStep ){
-    pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
+    if( IN_RENAME_OBJECT ){
+      pTriggerStep->pSelect = pSelect;
+      pSelect = 0;
+    }else{
+      pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
+    }
     pTriggerStep->pIdList = pColumn;
     pTriggerStep->pUpsert = pUpsert;
     pTriggerStep->orconf = orconf;
@@ -128300,7 +130379,7 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(
 ** sees an UPDATE statement inside the body of a CREATE TRIGGER.
 */
 SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(
-  sqlite3 *db,         /* The database connection */
+  Parse *pParse,          /* Parser */
   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 */
@@ -128308,12 +130387,20 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(
   const char *zStart,  /* Start of SQL text */
   const char *zEnd     /* End of SQL text */
 ){
+  sqlite3 *db = pParse->db;
   TriggerStep *pTriggerStep;
 
-  pTriggerStep = triggerStepAllocate(db, TK_UPDATE, pTableName, zStart, zEnd);
+  pTriggerStep = triggerStepAllocate(pParse, TK_UPDATE, pTableName,zStart,zEnd);
   if( pTriggerStep ){
-    pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
-    pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
+    if( IN_RENAME_OBJECT ){
+      pTriggerStep->pExprList = pEList;
+      pTriggerStep->pWhere = pWhere;
+      pEList = 0;
+      pWhere = 0;
+    }else{
+      pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
+      pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
+    }
     pTriggerStep->orconf = orconf;
   }
   sqlite3ExprListDelete(db, pEList);
@@ -128327,17 +130414,23 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(
 ** sees a DELETE statement inside the body of a CREATE TRIGGER.
 */
 SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep(
-  sqlite3 *db,            /* Database connection */
+  Parse *pParse,          /* Parser */
   Token *pTableName,      /* The table from which rows are deleted */
   Expr *pWhere,           /* The WHERE clause */
   const char *zStart,     /* Start of SQL text */
   const char *zEnd        /* End of SQL text */
 ){
+  sqlite3 *db = pParse->db;
   TriggerStep *pTriggerStep;
 
-  pTriggerStep = triggerStepAllocate(db, TK_DELETE, pTableName, zStart, zEnd);
+  pTriggerStep = triggerStepAllocate(pParse, TK_DELETE, pTableName,zStart,zEnd);
   if( pTriggerStep ){
-    pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
+    if( IN_RENAME_OBJECT ){
+      pTriggerStep->pWhere = pWhere;
+      pWhere = 0;
+    }else{
+      pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
+    }
     pTriggerStep->orconf = OE_Default;
   }
   sqlite3ExprDelete(db, pWhere);
@@ -129522,7 +131615,7 @@ SQLITE_PRIVATE void sqlite3Update(
       if( !isView && aiCurOnePass[0]!=iDataCur && aiCurOnePass[1]!=iDataCur ){
         assert( pPk );
         sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey,nKey);
-        VdbeCoverageNeverTaken(v);
+        VdbeCoverage(v);
       }
       if( eOnePass!=ONEPASS_SINGLE ){
         labelContinue = sqlite3VdbeMakeLabel(v);
@@ -129609,13 +131702,7 @@ SQLITE_PRIVATE void sqlite3Update(
         */
         testcase( i==31 );
         testcase( i==32 );
-        sqlite3ExprCodeGetColumnToReg(pParse, pTab, i, iDataCur, regNew+i);
-        if( tmask & TRIGGER_BEFORE ){
-          /* This value will be recomputed in After-BEFORE-trigger-reload-loop
-          ** below, so make sure that it is not cached and reused.
-          ** Ticket d85fffd6ffe856092ed8daefa811b1e399706b28. */
-          sqlite3ExprCacheRemove(pParse, regNew+i, 1);
-        }
+        sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i);
       }else{
         sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
       }
@@ -130152,10 +132239,12 @@ SQLITE_PRIVATE void sqlite3UpsertDoUpdate(
   Vdbe *v = pParse->pVdbe;
   sqlite3 *db = pParse->db;
   SrcList *pSrc;            /* FROM clause for the UPDATE */
-  int iDataCur = pUpsert->iDataCur;
+  int iDataCur;
 
   assert( v!=0 );
+  assert( pUpsert!=0 );
   VdbeNoopComment((v, "Begin DO UPDATE of UPSERT"));
+  iDataCur = pUpsert->iDataCur;
   if( pIdx && iCur!=iDataCur ){
     if( HasRowid(pTab) ){
       int regRowid = sqlite3GetTempReg(pParse);
@@ -130425,7 +132514,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
   */
   rc = execSql(db, pzErrMsg, "BEGIN");
   if( rc!=SQLITE_OK ) goto end_of_vacuum;
-  rc = sqlite3BtreeBeginTrans(pMain, 2);
+  rc = sqlite3BtreeBeginTrans(pMain, 2, 0);
   if( rc!=SQLITE_OK ) goto end_of_vacuum;
 
   /* Do not attempt to change the page size for a WAL database */
@@ -130843,7 +132932,7 @@ SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3 *db){
   assert( sqlite3_mutex_held(db->mutex) );
 
   if( p ){
-    sqlite3ExpirePreparedStatements(db);
+    sqlite3ExpirePreparedStatements(db, 0);
     do {
       VTable *pNext = p->pNext;
       sqlite3VtabUnlock(p);
@@ -131339,7 +133428,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
   assert( IsVirtual(pTab) );
 
   memset(&sParse, 0, sizeof(sParse));
-  sParse.declareVtab = 1;
+  sParse.eParseMode = PARSE_MODE_DECLARE_VTAB;
   sParse.db = db;
   sParse.nQueryLoop = 1;
   if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr) 
@@ -131380,7 +133469,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
     sqlite3DbFree(db, zErr);
     rc = SQLITE_ERROR;
   }
-  sParse.declareVtab = 0;
+  sParse.eParseMode = PARSE_MODE_NORMAL;
 
   if( sParse.pVdbe ){
     sqlite3VdbeFinalize(sParse.pVdbe);
@@ -131934,6 +134023,8 @@ struct WhereLevel {
       struct InLoop {
         int iCur;              /* The VDBE cursor used by this IN operator */
         int addrInTop;         /* Top of the IN loop */
+        int iBase;             /* Base register of multi-key index record */
+        int nPrefix;           /* Number of prior entires in the key */
         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 */
@@ -132172,6 +134263,7 @@ struct WhereClause {
   WhereInfo *pWInfo;       /* WHERE clause processing context */
   WhereClause *pOuter;     /* Outer conjunction */
   u8 op;                   /* Split operator.  TK_AND or TK_OR */
+  u8 hasOr;                /* True if any a[].eOperator is WO_OR */
   int nTerm;               /* Number of terms */
   int nSlot;               /* Number of entries in a[] */
   WhereTerm *a;            /* Each a[] describes a term of the WHERE cluase */
@@ -132345,6 +134437,7 @@ 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 sqlite3WhereExprUsageNN(WhereMaskSet*, Expr*);
 SQLITE_PRIVATE Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*);
 SQLITE_PRIVATE void sqlite3WhereExprAnalyze(SrcList*, WhereClause*);
 SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereClause*);
@@ -132407,6 +134500,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC
 #define WHERE_SKIPSCAN     0x00008000  /* Uses the skip-scan algorithm */
 #define WHERE_UNQ_WANTED   0x00010000  /* WHERE_ONEROW would have been helpful*/
 #define WHERE_PARTIALIDX   0x00020000  /* The automatic index is partial */
+#define WHERE_IN_EARLYOUT  0x00040000  /* Perhaps quit IN loops early */
 
 /************** End of whereInt.h ********************************************/
 /************** Continuing where we left off in wherecode.c ******************/
@@ -132541,7 +134635,7 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
     sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
     sqlite3_str_appendall(&str, isSearch ? "SEARCH" : "SCAN");
     if( pItem->pSelect ){
-      sqlite3_str_appendf(&str, " SUBQUERY 0x%p", pItem->pSelect);
+      sqlite3_str_appendf(&str, " SUBQUERY %u", pItem->pSelect->selId);
     }else{
       sqlite3_str_appendf(&str, " TABLE %s", pItem->zName);
     }
@@ -132738,7 +134832,6 @@ static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){
   /* 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);
   }
 }
 
@@ -132982,7 +135075,14 @@ static int codeEqualityTerm(
           sqlite3VdbeAddOp1(v, OP_IsNull, iOut); VdbeCoverage(v);
           if( i==iEq ){
             pIn->iCur = iTab;
-            pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen;
+            pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next;
+            if( iEq>0 && (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ){
+              pIn->iBase = iReg - i;
+              pIn->nPrefix = i;
+              pLoop->wsFlags |= WHERE_IN_EARLYOUT;
+            }else{
+              pIn->nPrefix = 0;
+            }
           }else{
             pIn->eEndLoopOp = OP_Noop;
           }
@@ -133269,11 +135369,8 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
   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
-      );
+      sqlite3ExprCode(pWalker->pParse, pExpr, reg);
       pExpr->op = TK_REGISTER;
       pExpr->iTable = reg;
     }else if( pHint->pIdx!=0 ){
@@ -133626,7 +135723,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
     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));
+    VdbeComment((v, "next row of %s", pTabItem->pTab->zName));
     pLevel->op = OP_Goto;
   }else
 
@@ -133640,7 +135737,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
     int nConstraint = pLoop->nLTerm;
     int iIn;    /* Counter for IN constraints */
 
-    sqlite3ExprCachePush(pParse);
     iReg = sqlite3GetTempRange(pParse, nConstraint+2);
     addrNotFound = pLevel->addrBrk;
     for(j=0; j<nConstraint; j++){
@@ -133713,7 +135809,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
     **
     **    sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
     */
-    sqlite3ExprCachePop(pParse);
   }else
 #endif /* SQLITE_OMIT_VIRTUALTABLE */
 
@@ -133737,9 +135832,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
     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
@@ -133809,7 +135901,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
       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);
@@ -133844,7 +135935,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
     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);
@@ -134049,6 +136139,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
       ** above has already left the cursor sitting on the correct row,
       ** so no further seeking is needed */
     }else{
+      if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){
+        sqlite3VdbeAddOp1(v, OP_SeekHit, iIdxCur);
+      }
       op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
       assert( op!=0 );
       sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
@@ -134067,7 +136160,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
     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
@@ -134092,7 +136184,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
       }
     }else if( bStopAtNull ){
       sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
-      sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
       endEq = 0;
       nConstraint++;
     }
@@ -134112,6 +136203,10 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
       testcase( op==OP_IdxLE );  VdbeCoverageIf(v, op==OP_IdxLE );
     }
 
+    if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){
+      sqlite3VdbeAddOp2(v, OP_SeekHit, iIdxCur, 1);
+    }
+
     /* Seek the table cursor, if required */
     if( omitTable ){
       /* pIdx is a covering index.  No need to access the main table. */
@@ -134122,7 +136217,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
       )){
         iRowidReg = ++pParse->nMem;
         sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
-        sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
         sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowidReg);
         VdbeCoverage(v);
       }else{
@@ -134357,23 +136451,23 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
           ** 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);
+              sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, regRowid);
               jmp1 = sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, 0,
-                                           r,iSet);
+                                          regRowid, iSet);
               VdbeCoverage(v);
             }else{
               Index *pPk = sqlite3PrimaryKeyIndex(pTab);
               int nPk = pPk->nKeyCol;
               int iPk;
+              int r;
 
               /* Read the PK into an array of temp registers. */
               r = sqlite3GetTempRange(pParse, nPk);
               for(iPk=0; iPk<nPk; iPk++){
                 int iCol = pPk->aiColumn[iPk];
-                sqlite3ExprCodeGetColumnToReg(pParse, pTab, iCol, iCur, r+iPk);
+                sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol, r+iPk);
               }
 
               /* Check if the temp table already contains this key. If so,
@@ -134606,7 +136700,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
     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; j<pWC->nTerm; j++, pTerm++){
       testcase( pTerm->wtFlags & TERM_VIRTUAL );
       testcase( pTerm->wtFlags & TERM_CODED );
@@ -134822,18 +136915,18 @@ static int isLikeOrGlob(
   int *pisComplete, /* True if the only wildcard is % in the last character */
   int *pnoCase      /* True if uppercase is equivalent to lowercase */
 ){
-  const u8 *z = 0;         /* String on RHS of LIKE operator */
+  const u8 *z = 0;           /* String on RHS of LIKE operator */
   Expr *pRight, *pLeft;      /* Right and left size of LIKE operator */
   ExprList *pList;           /* List of operands to the LIKE operator */
-  int c;                     /* One character in z[] */
+  u8 c;                      /* One character in z[] */
   int cnt;                   /* Number of non-wildcard prefix characters */
-  char wc[4];                /* Wildcard characters */
+  u8 wc[4];                  /* 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) ){
+  if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, (char*)wc) ){
     return 0;
   }
 #ifdef SQLITE_EBCDIC
@@ -134858,23 +136951,6 @@ static int isLikeOrGlob(
   }
   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;
-      }
-    }
-
     /* Count the number of prefix characters prior to the first wildcard */
     cnt = 0;
     while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
@@ -134884,11 +136960,13 @@ static int isLikeOrGlob(
 
     /* The optimization is possible only if (1) the pattern does not begin
     ** with a wildcard and if (2) the non-wildcard prefix does not end with
-    ** an (illegal 0xff) character.  The second condition is necessary so
+    ** an (illegal 0xff) character, or (3) the pattern does not consist of
+    ** a single escape character. The second condition is necessary so
     ** that we can increment the prefix key to find an upper bound for the
-    ** range search. 
-    */
-    if( cnt!=0 && 255!=(u8)z[cnt-1] ){
+    ** range search. The third is because the caller assumes that the pattern
+    ** consists of at least one character after all escapes have been
+    ** removed.  */
+    if( cnt!=0 && 255!=(u8)z[cnt-1] && (cnt>1 || z[0]!=wc[3]) ){
       Expr *pPrefix;
 
       /* A "complete" match if the pattern ends with "*" or "%" */
@@ -134905,6 +136983,32 @@ static int isLikeOrGlob(
           zNew[iTo++] = zNew[iFrom];
         }
         zNew[iTo] = 0;
+
+        /* 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.
+        **
+        ** 2018-09-10 ticket c94369cae9b561b1f996d0054bfab11389f9d033
+        ** The RHS pattern must not be '/%' because the termination condition
+        ** will then become "x<'0'" and if the affinity is numeric, will then
+        ** be converted into "x<0", which is incorrect.
+        */
+        if( sqlite3Isdigit(zNew[0])
+         || zNew[0]=='-'
+         || (zNew[0]+1=='0' && iTo==1)
+        ){
+          if( pLeft->op!=TK_COLUMN 
+           || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT 
+           || IsVirtual(pLeft->pTab)  /* Value might be numeric */
+          ){
+            sqlite3ExprDelete(db, pPrefix);
+            sqlite3ValueFree(pVal);
+            return 0;
+          }
+        }
       }
       *ppPrefix = pPrefix;
 
@@ -134966,6 +137070,7 @@ static int isLikeOrGlob(
 ** If the expression matches none of the patterns above, return 0.
 */
 static int isAuxiliaryVtabOperator(
+  sqlite3 *db,                    /* Parsing context */
   Expr *pExpr,                    /* Test this expression */
   unsigned char *peOp2,           /* OUT: 0 for MATCH, or else an op2 value */
   Expr **ppLeft,                  /* Column expression to left of MATCH/op2 */
@@ -134989,16 +137094,54 @@ static int isAuxiliaryVtabOperator(
     if( pList==0 || pList->nExpr!=2 ){
       return 0;
     }
+
+    /* Built-in operators MATCH, GLOB, LIKE, and REGEXP attach to a
+    ** virtual table on their second argument, which is the same as
+    ** the left-hand side operand in their in-fix form.
+    **
+    **       vtab_column MATCH expression
+    **       MATCH(expression,vtab_column)
+    */
     pCol = pList->a[1].pExpr;
-    if( pCol->op!=TK_COLUMN || !IsVirtual(pCol->pTab) ){
-      return 0;
+    if( pCol->op==TK_COLUMN && IsVirtual(pCol->pTab) ){
+      for(i=0; i<ArraySize(aOp); i++){
+        if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){
+          *peOp2 = aOp[i].eOp2;
+          *ppRight = pList->a[0].pExpr;
+          *ppLeft = pCol;
+          return 1;
+        }
+      }
     }
-    for(i=0; i<ArraySize(aOp); i++){
-      if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){
-        *peOp2 = aOp[i].eOp2;
-        *ppRight = pList->a[0].pExpr;
-        *ppLeft = pCol;
-        return 1;
+
+    /* We can also match against the first column of overloaded
+    ** functions where xFindFunction returns a value of at least
+    ** SQLITE_INDEX_CONSTRAINT_FUNCTION.
+    **
+    **      OVERLOADED(vtab_column,expression)
+    **
+    ** Historically, xFindFunction expected to see lower-case function
+    ** names.  But for this use case, xFindFunction is expected to deal
+    ** with function names in an arbitrary case.
+    */
+    pCol = pList->a[0].pExpr;
+    if( pCol->op==TK_COLUMN && IsVirtual(pCol->pTab) ){
+      sqlite3_vtab *pVtab;
+      sqlite3_module *pMod;
+      void (*xNotUsed)(sqlite3_context*,int,sqlite3_value**);
+      void *pNotUsed;
+      pVtab = sqlite3GetVTable(db, pCol->pTab)->pVtab;
+      assert( pVtab!=0 );
+      assert( pVtab->pModule!=0 );
+      pMod = (sqlite3_module *)pVtab->pModule;
+      if( pMod->xFindFunction!=0 ){
+        i = pMod->xFindFunction(pVtab,2, pExpr->u.zToken, &xNotUsed, &pNotUsed);
+        if( i>=SQLITE_INDEX_CONSTRAINT_FUNCTION ){
+          *peOp2 = i;
+          *ppRight = pList->a[1].pExpr;
+          *ppLeft = pCol;
+          return 1;
+        }
       }
     }
   }else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){
@@ -135300,7 +137443,12 @@ static void exprAnalyzeOrTerm(
   ** empty.
   */
   pOrInfo->indexable = indexable;
-  pTerm->eOperator = indexable==0 ? 0 : WO_OR;
+  if( indexable ){
+    pTerm->eOperator = WO_OR;
+    pWC->hasOr = 1;
+  }else{
+    pTerm->eOperator = WO_OR;
+  }
 
   /* For a two-way OR, attempt to implementation case 2.
   */
@@ -135441,7 +137589,7 @@ static void exprAnalyzeOrTerm(
         idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC);
         testcase( idxNew==0 );
         exprAnalyze(pSrc, pWC, idxNew);
-        pTerm = &pWC->a[idxTerm];
+        /* pTerm = &pWC->a[idxTerm]; // would be needed if pTerm where used again */
         markTermAsChild(pWC, idxNew, idxTerm);
       }else{
         sqlite3ExprListDelete(db, pList);
@@ -135480,7 +137628,7 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr){
     return 0;
   }
   pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight);
-  if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1;
+  if( sqlite3IsBinary(pColl) ) return 1;
   return sqlite3ExprCollSeqMatch(pParse, pExpr->pLeft, pExpr->pRight);
 }
 
@@ -135639,7 +137787,7 @@ static void exprAnalyze(
     pTerm->prereqRight = sqlite3WhereExprUsage(pMaskSet, pExpr->pRight);
   }
   pMaskSet->bVarSelect = 0;
-  prereqAll = sqlite3WhereExprUsage(pMaskSet, pExpr);
+  prereqAll = sqlite3WhereExprUsageNN(pMaskSet, pExpr);
   if( pMaskSet->bVarSelect ) pTerm->wtFlags |= TERM_VARSELECT;
   if( ExprHasProperty(pExpr, EP_FromJoin) ){
     Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->iRightJoinTable);
@@ -135821,7 +137969,7 @@ static void exprAnalyze(
       }
       *pC = c + 1;
     }
-    zCollSeqName = noCase ? "NOCASE" : "BINARY";
+    zCollSeqName = noCase ? "NOCASE" : sqlite3StrBINARY;
     pNewExpr1 = sqlite3ExprDup(db, pLeft, 0);
     pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
            sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName),
@@ -135858,7 +138006,7 @@ static void exprAnalyze(
   */
   if( pWC->op==TK_AND ){
     Expr *pRight = 0, *pLeft = 0;
-    int res = isAuxiliaryVtabOperator(pExpr, &eOp2, &pLeft, &pRight);
+    int res = isAuxiliaryVtabOperator(db, pExpr, &eOp2, &pLeft, &pRight);
     while( res-- > 0 ){
       int idxNew;
       WhereTerm *pNewTerm;
@@ -136032,6 +138180,7 @@ SQLITE_PRIVATE void sqlite3WhereClauseInit(
   WhereInfo *pWInfo        /* The WHERE processing context */
 ){
   pWC->pWInfo = pWInfo;
+  pWC->hasOr = 0;
   pWC->pOuter = 0;
   pWC->nTerm = 0;
   pWC->nSlot = ArraySize(pWC->aStatic);
@@ -136068,17 +138217,18 @@ SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause *pWC){
 ** a bitmask indicating which tables are used in that expression
 ** tree.
 */
-SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){
+SQLITE_PRIVATE Bitmask sqlite3WhereExprUsageNN(WhereMaskSet *pMaskSet, Expr *p){
   Bitmask mask;
-  if( p==0 ) return 0;
-  if( p->op==TK_COLUMN ){
+  if( p->op==TK_COLUMN && !ExprHasProperty(p, EP_FixedCol) ){
     return sqlite3WhereGetMask(pMaskSet, p->iTable);
+  }else if( ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){
+    assert( p->op!=TK_IF_NULL_ROW );
+    return 0;
   }
   mask = (p->op==TK_IF_NULL_ROW) ? sqlite3WhereGetMask(pMaskSet, p->iTable) : 0;
-  assert( !ExprHasProperty(p, EP_TokenOnly) );
-  if( p->pLeft ) mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft);
+  if( p->pLeft ) mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pLeft);
   if( p->pRight ){
-    mask |= sqlite3WhereExprUsage(pMaskSet, p->pRight);
+    mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pRight);
     assert( p->x.pList==0 );
   }else if( ExprHasProperty(p, EP_xIsSelect) ){
     if( ExprHasProperty(p, EP_VarSelect) ) pMaskSet->bVarSelect = 1;
@@ -136088,6 +138238,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){
   }
   return mask;
 }
+SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){
+  return p ? sqlite3WhereExprUsageNN(pMaskSet,p) : 0;
+}
 SQLITE_PRIVATE Bitmask sqlite3WhereExprListUsage(WhereMaskSet *pMaskSet, ExprList *pList){
   int i;
   Bitmask mask = 0;
@@ -136229,15 +138382,38 @@ SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
 }
 
 /*
-** Return TRUE if the innermost loop of the WHERE clause implementation
-** returns rows in ORDER BY order for complete run of the inner loop.
+** In the ORDER BY LIMIT optimization, if the inner-most loop is known
+** to emit rows in increasing order, and if the last row emitted by the
+** inner-most loop did not fit within the sorter, then we can skip all
+** subsequent rows for the current iteration of the inner loop (because they
+** will not fit in the sorter either) and continue with the second inner
+** loop - the loop immediately outside the inner-most.
 **
-** 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.
+** When a row does not fit in the sorter (because the sorter already
+** holds LIMIT+OFFSET rows that are smaller), then a jump is made to the
+** label returned by this function.
+**
+** If the ORDER BY LIMIT optimization applies, the jump destination should
+** be the continuation for the second-inner-most loop.  If the ORDER BY
+** LIMIT optimization does not apply, then the jump destination should
+** be the continuation for the inner-most loop.
+**
+** It is always safe for this routine to return the continuation of the
+** inner-most loop, in the sense that a correct answer will result.  
+** Returning the continuation the second inner loop is an optimization
+** that might make the code run a little faster, but should not change
+** the final answer.
 */
-SQLITE_PRIVATE int sqlite3WhereOrderedInnerLoop(WhereInfo *pWInfo){
-  return pWInfo->bOrderedInnerLoop;
+SQLITE_PRIVATE int sqlite3WhereOrderByLimitOptLabel(WhereInfo *pWInfo){
+  WhereLevel *pInner;
+  if( !pWInfo->bOrderedInnerLoop ){
+    /* The ORDER BY LIMIT optimization does not apply.  Jump to the 
+    ** continuation of the inner-most loop. */
+    return pWInfo->iContinue;
+  }
+  pInner = &pWInfo->a[pWInfo->nLevel-1];
+  assert( pInner->addrNxt!=0 );
+  return pInner->addrNxt;
 }
 
 /*
@@ -136964,7 +139140,6 @@ static void constructAutomaticIndex(
   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;
@@ -136972,7 +139147,7 @@ static void constructAutomaticIndex(
     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));
+    VdbeComment((v, "next row of %s", pTabItem->pTab->zName));
   }else{
     addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v);
   }
@@ -137001,7 +139176,6 @@ static void constructAutomaticIndex(
   sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
   sqlite3VdbeJumpHere(v, addrTop);
   sqlite3ReleaseTempReg(pParse, regRecord);
-  sqlite3ExprCachePop(pParse);
   
   /* Jump here when skipping the initialization */
   sqlite3VdbeJumpHere(v, addrInit);
@@ -137107,6 +139281,20 @@ static sqlite3_index_info *allocateIndexInfo(
     testcase( pTerm->eOperator & WO_ALL );
     if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
     if( pTerm->wtFlags & TERM_VNULL ) continue;
+    if( (pSrc->fg.jointype & JT_LEFT)!=0
+     && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
+     && (pTerm->eOperator & (WO_IS|WO_ISNULL))
+    ){
+      /* An "IS" term in the WHERE clause where the virtual table is the rhs
+      ** of a LEFT JOIN. Do not pass this term to the virtual table
+      ** implementation, as this can lead to incorrect results from SQL such
+      ** as:
+      **
+      **   "LEFT JOIN vtab WHERE vtab.col IS NULL"  */
+      testcase( pTerm->eOperator & WO_ISNULL );
+      testcase( pTerm->eOperator & WO_IS );
+      continue;
+    }
     assert( pTerm->u.leftColumn>=(-1) );
     pIdxCons[j].iColumn = pTerm->u.leftColumn;
     pIdxCons[j].iTermOffset = i;
@@ -137598,7 +139786,9 @@ static int whereRangeScanEst(
   Index *p = pLoop->u.btree.pIndex;
   int nEq = pLoop->u.btree.nEq;
 
-  if( p->nSample>0 && nEq<p->nSampleCol ){
+  if( p->nSample>0 && nEq<p->nSampleCol
+   && OptimizationEnabled(pParse->db, SQLITE_Stat34)
+  ){
     if( nEq==pBuilder->nRecValid ){
       UnpackedRecord *pRec = pBuilder->pRec;
       tRowcnt a[2];
@@ -138613,7 +140803,6 @@ static int whereLoopAddBtreeIndex(
 
     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;
@@ -138633,6 +140822,42 @@ static int whereLoopAddBtreeIndex(
         assert( nIn>0 );  /* RHS always has 2 or more terms...  The parser
                           ** changes "x IN (?)" into "x=?". */
       }
+      if( pProbe->hasStat1 ){
+        LogEst M, logK, safetyMargin;
+        /* Let:
+        **   N = the total number of rows in the table
+        **   K = the number of entries on the RHS of the IN operator
+        **   M = the number of rows in the table that match terms to the 
+        **       to the left in the same index.  If the IN operator is on
+        **       the left-most index column, M==N.
+        **
+        ** Given the definitions above, it is better to omit the IN operator
+        ** from the index lookup and instead do a scan of the M elements,
+        ** testing each scanned row against the IN operator separately, if:
+        **
+        **        M*log(K) < K*log(N)
+        **
+        ** Our estimates for M, K, and N might be inaccurate, so we build in
+        ** a safety margin of 2 (LogEst: 10) that favors using the IN operator
+        ** with the index, as using an index has better worst-case behavior.
+        ** If we do not have real sqlite_stat1 data, always prefer to use
+        ** the index.
+        */
+        M = pProbe->aiRowLogEst[saved_nEq];
+        logK = estLog(nIn);
+        safetyMargin = 10;  /* TUNING: extra weight for indexed IN */
+        if( M + logK + safetyMargin < nIn + rLogSize ){
+          WHERETRACE(0x40,
+            ("Scan preferred over IN operator on column %d of \"%s\" (%d<%d)\n",
+             saved_nEq, pProbe->zName, M+logK+10, nIn+rLogSize));
+          continue;
+        }else{
+          WHERETRACE(0x40,
+            ("IN operator preferred on column %d of \"%s\" (%d>=%d)\n",
+             saved_nEq, pProbe->zName, M+logK+10, nIn+rLogSize));
+        }
+      }
+      pNew->wsFlags |= WHERE_COLUMN_IN;
     }else if( eOp & (WO_EQ|WO_IS) ){
       int iCol = pProbe->aiColumn[saved_nEq];
       pNew->wsFlags |= WHERE_COLUMN_EQ;
@@ -138711,6 +140936,7 @@ static int whereLoopAddBtreeIndex(
          && pProbe->nSample 
          && pNew->u.btree.nEq<=pProbe->nSampleCol
          && ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect))
+         && OptimizationEnabled(db, SQLITE_Stat34)
         ){
           Expr *pExpr = pTerm->pExpr;
           if( (eOp & (WO_EQ|WO_ISNULL|WO_IS))!=0 ){
@@ -138799,6 +141025,7 @@ static int whereLoopAddBtreeIndex(
   if( saved_nEq==saved_nSkip
    && saved_nEq+1<pProbe->nKeyCol
    && pProbe->noSkipScan==0
+   && OptimizationEnabled(db, SQLITE_SkipScan)
    && pProbe->aiRowLogEst[saved_nEq+1]>=42  /* TUNING: Minimum for skip-scan */
    && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
   ){
@@ -138862,24 +141089,6 @@ static int indexMightHelpWithOrderBy(
   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( x<BMS-1 ) m |= MASKBIT(x);
-    }
-  }
-  return m;
-}
-
 /* Check to see if a partial index with pPartIndexWhere can be used
 ** in the current query.  Return true if it can be and false if not.
 */
@@ -139095,7 +141304,7 @@ static int whereLoopAddBtree(
         pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
         m = 0;
       }else{
-        m = pSrc->colUsed & ~columnsInIndex(pProbe);
+        m = pSrc->colUsed & pProbe->colNotIdxed;
         pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED;
       }
 
@@ -139346,7 +141555,7 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info *pIdxInfo, int
     if( pX->pLeft ){
       pC = sqlite3BinaryCompareCollSeq(pHidden->pParse, pX->pLeft, pX->pRight);
     }
-    zRet = (pC ? pC->zName : "BINARY");
+    zRet = (pC ? pC->zName : sqlite3StrBINARY);
   }
   return zRet;
 }
@@ -139662,7 +141871,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
     {
       rc = whereLoopAddBtree(pBuilder, mPrereq);
     }
-    if( rc==SQLITE_OK ){
+    if( rc==SQLITE_OK && pBuilder->pWC->hasOr ){
       rc = whereLoopAddOr(pBuilder, mPrereq, mUnusable);
     }
     mPrior |= pNew->maskSelf;
@@ -140197,7 +142406,11 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
                 pWInfo, nRowEst, nOrderBy, isOrdered
             );
           }
-          rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]);
+          /* TUNING:  Add a small extra penalty (5) to sorting as an
+          ** extra encouragment to the query planner to select a plan
+          ** where the rows emerge in the correct order without any sorting
+          ** required. */
+          rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]) + 5;
 
           WHERETRACE(0x002,
               ("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n",
@@ -140387,6 +142600,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
       pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
     }
   }
+  pWInfo->bOrderedInnerLoop = 0;
   if( pWInfo->pOrderBy ){
     if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){
       if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){
@@ -140498,7 +142712,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
       }
       if( j!=pIdx->nKeyCol ) continue;
       pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_ONEROW|WHERE_INDEXED;
-      if( pIdx->isCovering || (pItem->colUsed & ~columnsInIndex(pIdx))==0 ){
+      if( pIdx->isCovering || (pItem->colUsed & pIdx->colNotIdxed)==0 ){
         pLoop->wsFlags |= WHERE_IDX_ONLY;
       }
       pLoop->nLTerm = j;
@@ -141178,6 +143392,26 @@ whereBeginError:
   return 0;
 }
 
+/*
+** Part of sqlite3WhereEnd() will rewrite opcodes to reference the
+** index rather than the main table.  In SQLITE_DEBUG mode, we want
+** to trace those changes if PRAGMA vdbe_addoptrace=on.  This routine
+** does that.
+*/
+#ifndef SQLITE_DEBUG
+# define OpcodeRewriteTrace(D,K,P) /* no-op */
+#else
+# define OpcodeRewriteTrace(D,K,P) sqlite3WhereOpcodeRewriteTrace(D,K,P)
+  static void sqlite3WhereOpcodeRewriteTrace(
+    sqlite3 *db,
+    int pc,
+    VdbeOp *pOp
+  ){
+    if( (db->flags & SQLITE_VdbeAddopTrace)==0 ) return;
+    sqlite3VdbePrintOp(0, pc, pOp);
+  }
+#endif
+
 /*
 ** Generate the end of the WHERE loop.  See comments on 
 ** sqlite3WhereBegin() for additional information.
@@ -141194,7 +143428,6 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
   /* 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];
@@ -141245,10 +143478,17 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
       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 ){
+          if( pIn->nPrefix ){
+            assert( pLoop->wsFlags & WHERE_IN_EARLYOUT );
+            sqlite3VdbeAddOp4Int(v, OP_IfNoHope, pLevel->iIdxCur,
+                              sqlite3VdbeCurrentAddr(v)+2,
+                              pIn->iBase, pIn->nPrefix);
+            VdbeCoverage(v);
+          }
           sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop);
           VdbeCoverage(v);
-          VdbeCoverageIf(v, pIn->eEndLoopOp==OP_PrevIfOpen);
-          VdbeCoverageIf(v, pIn->eEndLoopOp==OP_NextIfOpen);
+          VdbeCoverageIf(v, pIn->eEndLoopOp==OP_Prev);
+          VdbeCoverageIf(v, pIn->eEndLoopOp==OP_Next);
         }
         sqlite3VdbeJumpHere(v, pIn->addrInTop-1);
       }
@@ -141339,6 +143579,11 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
     ){
       last = sqlite3VdbeCurrentAddr(v);
       k = pLevel->addrBody;
+#ifdef SQLITE_DEBUG
+      if( db->flags & SQLITE_VdbeAddopTrace ){
+        printf("TRANSLATE opcodes in range %d..%d\n", k, last-1);
+      }
+#endif
       pOp = sqlite3VdbeGetOp(v, k);
       for(; k<last; k++, pOp++){
         if( pOp->p1!=pLevel->iTabCur ) continue;
@@ -141358,16 +143603,22 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
           if( x>=0 ){
             pOp->p2 = x;
             pOp->p1 = pLevel->iIdxCur;
+            OpcodeRewriteTrace(db, k, pOp);
           }
           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;
+          OpcodeRewriteTrace(db, k, pOp);
         }else if( pOp->opcode==OP_IfNullRow ){
           pOp->p1 = pLevel->iIdxCur;
+          OpcodeRewriteTrace(db, k, pOp);
         }
       }
+#ifdef SQLITE_DEBUG
+      if( db->flags & SQLITE_VdbeAddopTrace ) printf("TRANSLATE complete\n");
+#endif
     }
   }
 
@@ -141379,6 +143630,2261 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
 }
 
 /************** End of where.c ***********************************************/
+/************** Begin file window.c ******************************************/
+/*
+** 2018 May 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.
+**
+*************************************************************************
+*/
+/* #include "sqliteInt.h" */
+
+#ifndef SQLITE_OMIT_WINDOWFUNC
+
+/*
+** SELECT REWRITING
+**
+**   Any SELECT statement that contains one or more window functions in
+**   either the select list or ORDER BY clause (the only two places window
+**   functions may be used) is transformed by function sqlite3WindowRewrite()
+**   in order to support window function processing. For example, with the
+**   schema:
+**
+**     CREATE TABLE t1(a, b, c, d, e, f, g);
+**
+**   the statement:
+**
+**     SELECT a+1, max(b) OVER (PARTITION BY c ORDER BY d) FROM t1 ORDER BY e;
+**
+**   is transformed to:
+**
+**     SELECT a+1, max(b) OVER (PARTITION BY c ORDER BY d) FROM (
+**         SELECT a, e, c, d, b FROM t1 ORDER BY c, d
+**     ) ORDER BY e;
+**
+**   The flattening optimization is disabled when processing this transformed
+**   SELECT statement. This allows the implementation of the window function
+**   (in this case max()) to process rows sorted in order of (c, d), which
+**   makes things easier for obvious reasons. More generally:
+**
+**     * FROM, WHERE, GROUP BY and HAVING clauses are all moved to 
+**       the sub-query.
+**
+**     * ORDER BY, LIMIT and OFFSET remain part of the parent query.
+**
+**     * Terminals from each of the expression trees that make up the 
+**       select-list and ORDER BY expressions in the parent query are
+**       selected by the sub-query. For the purposes of the transformation,
+**       terminals are column references and aggregate functions.
+**
+**   If there is more than one window function in the SELECT that uses
+**   the same window declaration (the OVER bit), then a single scan may
+**   be used to process more than one window function. For example:
+**
+**     SELECT max(b) OVER (PARTITION BY c ORDER BY d), 
+**            min(e) OVER (PARTITION BY c ORDER BY d) 
+**     FROM t1;
+**
+**   is transformed in the same way as the example above. However:
+**
+**     SELECT max(b) OVER (PARTITION BY c ORDER BY d), 
+**            min(e) OVER (PARTITION BY a ORDER BY b) 
+**     FROM t1;
+**
+**   Must be transformed to:
+**
+**     SELECT max(b) OVER (PARTITION BY c ORDER BY d) FROM (
+**         SELECT e, min(e) OVER (PARTITION BY a ORDER BY b), c, d, b FROM
+**           SELECT a, e, c, d, b FROM t1 ORDER BY a, b
+**         ) ORDER BY c, d
+**     ) ORDER BY e;
+**
+**   so that both min() and max() may process rows in the order defined by
+**   their respective window declarations.
+**
+** INTERFACE WITH SELECT.C
+**
+**   When processing the rewritten SELECT statement, code in select.c calls
+**   sqlite3WhereBegin() to begin iterating through the results of the
+**   sub-query, which is always implemented as a co-routine. It then calls
+**   sqlite3WindowCodeStep() to process rows and finish the scan by calling
+**   sqlite3WhereEnd().
+**
+**   sqlite3WindowCodeStep() generates VM code so that, for each row returned
+**   by the sub-query a sub-routine (OP_Gosub) coded by select.c is invoked.
+**   When the sub-routine is invoked:
+**
+**     * The results of all window-functions for the row are stored
+**       in the associated Window.regResult registers.
+**
+**     * The required terminal values are stored in the current row of
+**       temp table Window.iEphCsr.
+**
+**   In some cases, depending on the window frame and the specific window
+**   functions invoked, sqlite3WindowCodeStep() caches each entire partition
+**   in a temp table before returning any rows. In other cases it does not.
+**   This detail is encapsulated within this file, the code generated by
+**   select.c is the same in either case.
+**
+** BUILT-IN WINDOW FUNCTIONS
+**
+**   This implementation features the following built-in window functions:
+**
+**     row_number()
+**     rank()
+**     dense_rank()
+**     percent_rank()
+**     cume_dist()
+**     ntile(N)
+**     lead(expr [, offset [, default]])
+**     lag(expr [, offset [, default]])
+**     first_value(expr)
+**     last_value(expr)
+**     nth_value(expr, N)
+**   
+**   These are the same built-in window functions supported by Postgres. 
+**   Although the behaviour of aggregate window functions (functions that
+**   can be used as either aggregates or window funtions) allows them to
+**   be implemented using an API, built-in window functions are much more
+**   esoteric. Additionally, some window functions (e.g. nth_value()) 
+**   may only be implemented by caching the entire partition in memory.
+**   As such, some built-in window functions use the same API as aggregate
+**   window functions and some are implemented directly using VDBE 
+**   instructions. Additionally, for those functions that use the API, the
+**   window frame is sometimes modified before the SELECT statement is
+**   rewritten. For example, regardless of the specified window frame, the
+**   row_number() function always uses:
+**
+**     ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+**
+**   See sqlite3WindowUpdate() for details.
+**
+**   As well as some of the built-in window functions, aggregate window
+**   functions min() and max() are implemented using VDBE instructions if
+**   the start of the window frame is declared as anything other than 
+**   UNBOUNDED PRECEDING.
+*/
+
+/*
+** Implementation of built-in window function row_number(). Assumes that the
+** window frame has been coerced to:
+**
+**   ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+*/
+static void row_numberStepFunc(
+  sqlite3_context *pCtx, 
+  int nArg,
+  sqlite3_value **apArg
+){
+  i64 *p = (i64*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+  if( p ) (*p)++;
+  UNUSED_PARAMETER(nArg);
+  UNUSED_PARAMETER(apArg);
+}
+static void row_numberValueFunc(sqlite3_context *pCtx){
+  i64 *p = (i64*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+  sqlite3_result_int64(pCtx, (p ? *p : 0));
+}
+
+/*
+** Context object type used by rank(), dense_rank(), percent_rank() and
+** cume_dist().
+*/
+struct CallCount {
+  i64 nValue;
+  i64 nStep;
+  i64 nTotal;
+};
+
+/*
+** Implementation of built-in window function dense_rank(). Assumes that
+** the window frame has been set to:
+**
+**   RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 
+*/
+static void dense_rankStepFunc(
+  sqlite3_context *pCtx, 
+  int nArg,
+  sqlite3_value **apArg
+){
+  struct CallCount *p;
+  p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+  if( p ) p->nStep = 1;
+  UNUSED_PARAMETER(nArg);
+  UNUSED_PARAMETER(apArg);
+}
+static void dense_rankValueFunc(sqlite3_context *pCtx){
+  struct CallCount *p;
+  p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+  if( p ){
+    if( p->nStep ){
+      p->nValue++;
+      p->nStep = 0;
+    }
+    sqlite3_result_int64(pCtx, p->nValue);
+  }
+}
+
+/*
+** Implementation of built-in window function rank(). Assumes that
+** the window frame has been set to:
+**
+**   RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 
+*/
+static void rankStepFunc(
+  sqlite3_context *pCtx, 
+  int nArg,
+  sqlite3_value **apArg
+){
+  struct CallCount *p;
+  p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+  if( p ){
+    p->nStep++;
+    if( p->nValue==0 ){
+      p->nValue = p->nStep;
+    }
+  }
+  UNUSED_PARAMETER(nArg);
+  UNUSED_PARAMETER(apArg);
+}
+static void rankValueFunc(sqlite3_context *pCtx){
+  struct CallCount *p;
+  p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+  if( p ){
+    sqlite3_result_int64(pCtx, p->nValue);
+    p->nValue = 0;
+  }
+}
+
+/*
+** Implementation of built-in window function percent_rank(). Assumes that
+** the window frame has been set to:
+**
+**   RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 
+*/
+static void percent_rankStepFunc(
+  sqlite3_context *pCtx, 
+  int nArg,
+  sqlite3_value **apArg
+){
+  struct CallCount *p;
+  UNUSED_PARAMETER(nArg); assert( nArg==1 );
+
+  p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+  if( p ){
+    if( p->nTotal==0 ){
+      p->nTotal = sqlite3_value_int64(apArg[0]);
+    }
+    p->nStep++;
+    if( p->nValue==0 ){
+      p->nValue = p->nStep;
+    }
+  }
+}
+static void percent_rankValueFunc(sqlite3_context *pCtx){
+  struct CallCount *p;
+  p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+  if( p ){
+    if( p->nTotal>1 ){
+      double r = (double)(p->nValue-1) / (double)(p->nTotal-1);
+      sqlite3_result_double(pCtx, r);
+    }else{
+      sqlite3_result_double(pCtx, 0.0);
+    }
+    p->nValue = 0;
+  }
+}
+
+/*
+** Implementation of built-in window function cume_dist(). Assumes that
+** the window frame has been set to:
+**
+**   RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 
+*/
+static void cume_distStepFunc(
+  sqlite3_context *pCtx, 
+  int nArg,
+  sqlite3_value **apArg
+){
+  struct CallCount *p;
+  assert( nArg==1 ); UNUSED_PARAMETER(nArg);
+
+  p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+  if( p ){
+    if( p->nTotal==0 ){
+      p->nTotal = sqlite3_value_int64(apArg[0]);
+    }
+    p->nStep++;
+  }
+}
+static void cume_distValueFunc(sqlite3_context *pCtx){
+  struct CallCount *p;
+  p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+  if( p && p->nTotal ){
+    double r = (double)(p->nStep) / (double)(p->nTotal);
+    sqlite3_result_double(pCtx, r);
+  }
+}
+
+/*
+** Context object for ntile() window function.
+*/
+struct NtileCtx {
+  i64 nTotal;                     /* Total rows in partition */
+  i64 nParam;                     /* Parameter passed to ntile(N) */
+  i64 iRow;                       /* Current row */
+};
+
+/*
+** Implementation of ntile(). This assumes that the window frame has
+** been coerced to:
+**
+**   ROWS UNBOUNDED PRECEDING AND CURRENT ROW
+*/
+static void ntileStepFunc(
+  sqlite3_context *pCtx, 
+  int nArg,
+  sqlite3_value **apArg
+){
+  struct NtileCtx *p;
+  assert( nArg==2 ); UNUSED_PARAMETER(nArg);
+  p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+  if( p ){
+    if( p->nTotal==0 ){
+      p->nParam = sqlite3_value_int64(apArg[0]);
+      p->nTotal = sqlite3_value_int64(apArg[1]);
+      if( p->nParam<=0 ){
+        sqlite3_result_error(
+            pCtx, "argument of ntile must be a positive integer", -1
+        );
+      }
+    }
+    p->iRow++;
+  }
+}
+static void ntileValueFunc(sqlite3_context *pCtx){
+  struct NtileCtx *p;
+  p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+  if( p && p->nParam>0 ){
+    int nSize = (p->nTotal / p->nParam);
+    if( nSize==0 ){
+      sqlite3_result_int64(pCtx, p->iRow);
+    }else{
+      i64 nLarge = p->nTotal - p->nParam*nSize;
+      i64 iSmall = nLarge*(nSize+1);
+      i64 iRow = p->iRow-1;
+
+      assert( (nLarge*(nSize+1) + (p->nParam-nLarge)*nSize)==p->nTotal );
+
+      if( iRow<iSmall ){
+        sqlite3_result_int64(pCtx, 1 + iRow/(nSize+1));
+      }else{
+        sqlite3_result_int64(pCtx, 1 + nLarge + (iRow-iSmall)/nSize);
+      }
+    }
+  }
+}
+
+/*
+** Context object for last_value() window function.
+*/
+struct LastValueCtx {
+  sqlite3_value *pVal;
+  int nVal;
+};
+
+/*
+** Implementation of last_value().
+*/
+static void last_valueStepFunc(
+  sqlite3_context *pCtx, 
+  int nArg,
+  sqlite3_value **apArg
+){
+  struct LastValueCtx *p;
+  UNUSED_PARAMETER(nArg);
+  p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+  if( p ){
+    sqlite3_value_free(p->pVal);
+    p->pVal = sqlite3_value_dup(apArg[0]);
+    if( p->pVal==0 ){
+      sqlite3_result_error_nomem(pCtx);
+    }else{
+      p->nVal++;
+    }
+  }
+}
+static void last_valueInvFunc(
+  sqlite3_context *pCtx, 
+  int nArg,
+  sqlite3_value **apArg
+){
+  struct LastValueCtx *p;
+  UNUSED_PARAMETER(nArg);
+  UNUSED_PARAMETER(apArg);
+  p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+  if( ALWAYS(p) ){
+    p->nVal--;
+    if( p->nVal==0 ){
+      sqlite3_value_free(p->pVal);
+      p->pVal = 0;
+    }
+  }
+}
+static void last_valueValueFunc(sqlite3_context *pCtx){
+  struct LastValueCtx *p;
+  p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+  if( p && p->pVal ){
+    sqlite3_result_value(pCtx, p->pVal);
+  }
+}
+static void last_valueFinalizeFunc(sqlite3_context *pCtx){
+  struct LastValueCtx *p;
+  p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
+  if( p && p->pVal ){
+    sqlite3_result_value(pCtx, p->pVal);
+    sqlite3_value_free(p->pVal);
+    p->pVal = 0;
+  }
+}
+
+/*
+** Static names for the built-in window function names.  These static
+** names are used, rather than string literals, so that FuncDef objects
+** can be associated with a particular window function by direct
+** comparison of the zName pointer.  Example:
+**
+**       if( pFuncDef->zName==row_valueName ){ ... }
+*/
+static const char row_numberName[] =   "row_number";
+static const char dense_rankName[] =   "dense_rank";
+static const char rankName[] =         "rank";
+static const char percent_rankName[] = "percent_rank";
+static const char cume_distName[] =    "cume_dist";
+static const char ntileName[] =        "ntile";
+static const char last_valueName[] =   "last_value";
+static const char nth_valueName[] =    "nth_value";
+static const char first_valueName[] =  "first_value";
+static const char leadName[] =         "lead";
+static const char lagName[] =          "lag";
+
+/*
+** No-op implementations of xStep() and xFinalize().  Used as place-holders
+** for built-in window functions that never call those interfaces.
+**
+** The noopValueFunc() is called but is expected to do nothing.  The
+** noopStepFunc() is never called, and so it is marked with NO_TEST to
+** let the test coverage routine know not to expect this function to be
+** invoked.
+*/
+static void noopStepFunc(    /*NO_TEST*/
+  sqlite3_context *p,        /*NO_TEST*/
+  int n,                     /*NO_TEST*/
+  sqlite3_value **a          /*NO_TEST*/
+){                           /*NO_TEST*/
+  UNUSED_PARAMETER(p);       /*NO_TEST*/
+  UNUSED_PARAMETER(n);       /*NO_TEST*/
+  UNUSED_PARAMETER(a);       /*NO_TEST*/
+  assert(0);                 /*NO_TEST*/
+}                            /*NO_TEST*/
+static void noopValueFunc(sqlite3_context *p){ UNUSED_PARAMETER(p); /*no-op*/ }
+
+/* Window functions that use all window interfaces: xStep, xFinal,
+** xValue, and xInverse */
+#define WINDOWFUNCALL(name,nArg,extra) {                                   \
+  nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0,                      \
+  name ## StepFunc, name ## FinalizeFunc, name ## ValueFunc,               \
+  name ## InvFunc, name ## Name, {0}                                       \
+}
+
+/* Window functions that are implemented using bytecode and thus have
+** no-op routines for their methods */
+#define WINDOWFUNCNOOP(name,nArg,extra) {                                  \
+  nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0,                      \
+  noopStepFunc, noopValueFunc, noopValueFunc,                              \
+  noopStepFunc, name ## Name, {0}                                          \
+}
+
+/* Window functions that use all window interfaces: xStep, the
+** same routine for xFinalize and xValue and which never call
+** xInverse. */
+#define WINDOWFUNCX(name,nArg,extra) {                                     \
+  nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0,                      \
+  name ## StepFunc, name ## ValueFunc, name ## ValueFunc,                  \
+  noopStepFunc, name ## Name, {0}                                          \
+}
+
+
+/*
+** Register those built-in window functions that are not also aggregates.
+*/
+SQLITE_PRIVATE void sqlite3WindowFunctions(void){
+  static FuncDef aWindowFuncs[] = {
+    WINDOWFUNCX(row_number, 0, 0),
+    WINDOWFUNCX(dense_rank, 0, 0),
+    WINDOWFUNCX(rank, 0, 0),
+    WINDOWFUNCX(percent_rank, 0, SQLITE_FUNC_WINDOW_SIZE),
+    WINDOWFUNCX(cume_dist, 0, SQLITE_FUNC_WINDOW_SIZE),
+    WINDOWFUNCX(ntile, 1, SQLITE_FUNC_WINDOW_SIZE),
+    WINDOWFUNCALL(last_value, 1, 0),
+    WINDOWFUNCNOOP(nth_value, 2, 0),
+    WINDOWFUNCNOOP(first_value, 1, 0),
+    WINDOWFUNCNOOP(lead, 1, 0),
+    WINDOWFUNCNOOP(lead, 2, 0),
+    WINDOWFUNCNOOP(lead, 3, 0),
+    WINDOWFUNCNOOP(lag, 1, 0),
+    WINDOWFUNCNOOP(lag, 2, 0),
+    WINDOWFUNCNOOP(lag, 3, 0),
+  };
+  sqlite3InsertBuiltinFuncs(aWindowFuncs, ArraySize(aWindowFuncs));
+}
+
+/*
+** This function is called immediately after resolving the function name
+** for a window function within a SELECT statement. Argument pList is a
+** linked list of WINDOW definitions for the current SELECT statement.
+** Argument pFunc is the function definition just resolved and pWin
+** is the Window object representing the associated OVER clause. This
+** function updates the contents of pWin as follows:
+**
+**   * If the OVER clause refered to a named window (as in "max(x) OVER win"),
+**     search list pList for a matching WINDOW definition, and update pWin
+**     accordingly. If no such WINDOW clause can be found, leave an error
+**     in pParse.
+**
+**   * If the function is a built-in window function that requires the
+**     window to be coerced (see "BUILT-IN WINDOW FUNCTIONS" at the top
+**     of this file), pWin is updated here.
+*/
+SQLITE_PRIVATE void sqlite3WindowUpdate(
+  Parse *pParse, 
+  Window *pList,                  /* List of named windows for this SELECT */
+  Window *pWin,                   /* Window frame to update */
+  FuncDef *pFunc                  /* Window function definition */
+){
+  if( pWin->zName && pWin->eType==0 ){
+    Window *p;
+    for(p=pList; p; p=p->pNextWin){
+      if( sqlite3StrICmp(p->zName, pWin->zName)==0 ) break;
+    }
+    if( p==0 ){
+      sqlite3ErrorMsg(pParse, "no such window: %s", pWin->zName);
+      return;
+    }
+    pWin->pPartition = sqlite3ExprListDup(pParse->db, p->pPartition, 0);
+    pWin->pOrderBy = sqlite3ExprListDup(pParse->db, p->pOrderBy, 0);
+    pWin->pStart = sqlite3ExprDup(pParse->db, p->pStart, 0);
+    pWin->pEnd = sqlite3ExprDup(pParse->db, p->pEnd, 0);
+    pWin->eStart = p->eStart;
+    pWin->eEnd = p->eEnd;
+    pWin->eType = p->eType;
+  }
+  if( pFunc->funcFlags & SQLITE_FUNC_WINDOW ){
+    sqlite3 *db = pParse->db;
+    if( pWin->pFilter ){
+      sqlite3ErrorMsg(pParse, 
+          "FILTER clause may only be used with aggregate window functions"
+      );
+    }else
+    if( pFunc->zName==row_numberName || pFunc->zName==ntileName ){
+      sqlite3ExprDelete(db, pWin->pStart);
+      sqlite3ExprDelete(db, pWin->pEnd);
+      pWin->pStart = pWin->pEnd = 0;
+      pWin->eType = TK_ROWS;
+      pWin->eStart = TK_UNBOUNDED;
+      pWin->eEnd = TK_CURRENT;
+    }else
+
+    if( pFunc->zName==dense_rankName || pFunc->zName==rankName
+     || pFunc->zName==percent_rankName || pFunc->zName==cume_distName
+    ){
+      sqlite3ExprDelete(db, pWin->pStart);
+      sqlite3ExprDelete(db, pWin->pEnd);
+      pWin->pStart = pWin->pEnd = 0;
+      pWin->eType = TK_RANGE;
+      pWin->eStart = TK_UNBOUNDED;
+      pWin->eEnd = TK_CURRENT;
+    }
+  }
+  pWin->pFunc = pFunc;
+}
+
+/*
+** Context object passed through sqlite3WalkExprList() to
+** selectWindowRewriteExprCb() by selectWindowRewriteEList().
+*/
+typedef struct WindowRewrite WindowRewrite;
+struct WindowRewrite {
+  Window *pWin;
+  SrcList *pSrc;
+  ExprList *pSub;
+  Select *pSubSelect;             /* Current sub-select, if any */
+};
+
+/*
+** Callback function used by selectWindowRewriteEList(). If necessary,
+** this function appends to the output expression-list and updates 
+** expression (*ppExpr) in place.
+*/
+static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
+  struct WindowRewrite *p = pWalker->u.pRewrite;
+  Parse *pParse = pWalker->pParse;
+
+  /* If this function is being called from within a scalar sub-select
+  ** that used by the SELECT statement being processed, only process
+  ** TK_COLUMN expressions that refer to it (the outer SELECT). Do
+  ** not process aggregates or window functions at all, as they belong
+  ** to the scalar sub-select.  */
+  if( p->pSubSelect ){
+    if( pExpr->op!=TK_COLUMN ){
+      return WRC_Continue;
+    }else{
+      int nSrc = p->pSrc->nSrc;
+      int i;
+      for(i=0; i<nSrc; i++){
+        if( pExpr->iTable==p->pSrc->a[i].iCursor ) break;
+      }
+      if( i==nSrc ) return WRC_Continue;
+    }
+  }
+
+  switch( pExpr->op ){
+
+    case TK_FUNCTION:
+      if( pExpr->pWin==0 ){
+        break;
+      }else{
+        Window *pWin;
+        for(pWin=p->pWin; pWin; pWin=pWin->pNextWin){
+          if( pExpr->pWin==pWin ){
+            assert( pWin->pOwner==pExpr );
+            return WRC_Prune;
+          }
+        }
+      }
+      /* Fall through.  */
+
+    case TK_AGG_FUNCTION:
+    case TK_COLUMN: {
+      Expr *pDup = sqlite3ExprDup(pParse->db, pExpr, 0);
+      p->pSub = sqlite3ExprListAppend(pParse, p->pSub, pDup);
+      if( p->pSub ){
+        assert( ExprHasProperty(pExpr, EP_Static)==0 );
+        ExprSetProperty(pExpr, EP_Static);
+        sqlite3ExprDelete(pParse->db, pExpr);
+        ExprClearProperty(pExpr, EP_Static);
+        memset(pExpr, 0, sizeof(Expr));
+
+        pExpr->op = TK_COLUMN;
+        pExpr->iColumn = p->pSub->nExpr-1;
+        pExpr->iTable = p->pWin->iEphCsr;
+      }
+
+      break;
+    }
+
+    default: /* no-op */
+      break;
+  }
+
+  return WRC_Continue;
+}
+static int selectWindowRewriteSelectCb(Walker *pWalker, Select *pSelect){
+  struct WindowRewrite *p = pWalker->u.pRewrite;
+  Select *pSave = p->pSubSelect;
+  if( pSave==pSelect ){
+    return WRC_Continue;
+  }else{
+    p->pSubSelect = pSelect;
+    sqlite3WalkSelect(pWalker, pSelect);
+    p->pSubSelect = pSave;
+  }
+  return WRC_Prune;
+}
+
+
+/*
+** Iterate through each expression in expression-list pEList. For each:
+**
+**   * TK_COLUMN,
+**   * aggregate function, or
+**   * window function with a Window object that is not a member of the 
+**     Window list passed as the second argument (pWin).
+**
+** Append the node to output expression-list (*ppSub). And replace it
+** with a TK_COLUMN that reads the (N-1)th element of table 
+** pWin->iEphCsr, where N is the number of elements in (*ppSub) after
+** appending the new one.
+*/
+static void selectWindowRewriteEList(
+  Parse *pParse, 
+  Window *pWin,
+  SrcList *pSrc,
+  ExprList *pEList,               /* Rewrite expressions in this list */
+  ExprList **ppSub                /* IN/OUT: Sub-select expression-list */
+){
+  Walker sWalker;
+  WindowRewrite sRewrite;
+
+  memset(&sWalker, 0, sizeof(Walker));
+  memset(&sRewrite, 0, sizeof(WindowRewrite));
+
+  sRewrite.pSub = *ppSub;
+  sRewrite.pWin = pWin;
+  sRewrite.pSrc = pSrc;
+
+  sWalker.pParse = pParse;
+  sWalker.xExprCallback = selectWindowRewriteExprCb;
+  sWalker.xSelectCallback = selectWindowRewriteSelectCb;
+  sWalker.u.pRewrite = &sRewrite;
+
+  (void)sqlite3WalkExprList(&sWalker, pEList);
+
+  *ppSub = sRewrite.pSub;
+}
+
+/*
+** Append a copy of each expression in expression-list pAppend to
+** expression list pList. Return a pointer to the result list.
+*/
+static ExprList *exprListAppendList(
+  Parse *pParse,          /* Parsing context */
+  ExprList *pList,        /* List to which to append. Might be NULL */
+  ExprList *pAppend       /* List of values to append. Might be NULL */
+){
+  if( pAppend ){
+    int i;
+    int nInit = pList ? pList->nExpr : 0;
+    for(i=0; i<pAppend->nExpr; i++){
+      Expr *pDup = sqlite3ExprDup(pParse->db, pAppend->a[i].pExpr, 0);
+      pList = sqlite3ExprListAppend(pParse, pList, pDup);
+      if( pList ) pList->a[nInit+i].sortOrder = pAppend->a[i].sortOrder;
+    }
+  }
+  return pList;
+}
+
+/*
+** If the SELECT statement passed as the second argument does not invoke
+** any SQL window functions, this function is a no-op. Otherwise, it 
+** rewrites the SELECT statement so that window function xStep functions
+** are invoked in the correct order as described under "SELECT REWRITING"
+** at the top of this file.
+*/
+SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){
+  int rc = SQLITE_OK;
+  if( p->pWin ){
+    Vdbe *v = sqlite3GetVdbe(pParse);
+    sqlite3 *db = pParse->db;
+    Select *pSub = 0;             /* The subquery */
+    SrcList *pSrc = p->pSrc;
+    Expr *pWhere = p->pWhere;
+    ExprList *pGroupBy = p->pGroupBy;
+    Expr *pHaving = p->pHaving;
+    ExprList *pSort = 0;
+
+    ExprList *pSublist = 0;       /* Expression list for sub-query */
+    Window *pMWin = p->pWin;      /* Master window object */
+    Window *pWin;                 /* Window object iterator */
+
+    p->pSrc = 0;
+    p->pWhere = 0;
+    p->pGroupBy = 0;
+    p->pHaving = 0;
+
+    /* Create the ORDER BY clause for the sub-select. This is the concatenation
+    ** of the window PARTITION and ORDER BY clauses. Then, if this makes it
+    ** redundant, remove the ORDER BY from the parent SELECT.  */
+    pSort = sqlite3ExprListDup(db, pMWin->pPartition, 0);
+    pSort = exprListAppendList(pParse, pSort, pMWin->pOrderBy);
+    if( pSort && p->pOrderBy ){
+      if( sqlite3ExprListCompare(pSort, p->pOrderBy, -1)==0 ){
+        sqlite3ExprListDelete(db, p->pOrderBy);
+        p->pOrderBy = 0;
+      }
+    }
+
+    /* Assign a cursor number for the ephemeral table used to buffer rows.
+    ** The OpenEphemeral instruction is coded later, after it is known how
+    ** many columns the table will have.  */
+    pMWin->iEphCsr = pParse->nTab++;
+
+    selectWindowRewriteEList(pParse, pMWin, pSrc, p->pEList, &pSublist);
+    selectWindowRewriteEList(pParse, pMWin, pSrc, p->pOrderBy, &pSublist);
+    pMWin->nBufferCol = (pSublist ? pSublist->nExpr : 0);
+
+    /* Append the PARTITION BY and ORDER BY expressions to the to the 
+    ** sub-select expression list. They are required to figure out where 
+    ** boundaries for partitions and sets of peer rows lie.  */
+    pSublist = exprListAppendList(pParse, pSublist, pMWin->pPartition);
+    pSublist = exprListAppendList(pParse, pSublist, pMWin->pOrderBy);
+
+    /* Append the arguments passed to each window function to the
+    ** sub-select expression list. Also allocate two registers for each
+    ** window function - one for the accumulator, another for interim
+    ** results.  */
+    for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
+      pWin->iArgCol = (pSublist ? pSublist->nExpr : 0);
+      pSublist = exprListAppendList(pParse, pSublist, pWin->pOwner->x.pList);
+      if( pWin->pFilter ){
+        Expr *pFilter = sqlite3ExprDup(db, pWin->pFilter, 0);
+        pSublist = sqlite3ExprListAppend(pParse, pSublist, pFilter);
+      }
+      pWin->regAccum = ++pParse->nMem;
+      pWin->regResult = ++pParse->nMem;
+      sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum);
+    }
+
+    /* If there is no ORDER BY or PARTITION BY clause, and the window
+    ** function accepts zero arguments, and there are no other columns
+    ** selected (e.g. "SELECT row_number() OVER () FROM t1"), it is possible
+    ** that pSublist is still NULL here. Add a constant expression here to 
+    ** keep everything legal in this case. 
+    */
+    if( pSublist==0 ){
+      pSublist = sqlite3ExprListAppend(pParse, 0, 
+          sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[0], 0)
+      );
+    }
+
+    pSub = sqlite3SelectNew(
+        pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0
+    );
+    p->pSrc = sqlite3SrcListAppend(db, 0, 0, 0);
+    assert( p->pSrc || db->mallocFailed );
+    if( p->pSrc ){
+      p->pSrc->a[0].pSelect = pSub;
+      sqlite3SrcListAssignCursors(pParse, p->pSrc);
+      if( sqlite3ExpandSubquery(pParse, &p->pSrc->a[0]) ){
+        rc = SQLITE_NOMEM;
+      }else{
+        pSub->selFlags |= SF_Expanded;
+        p->selFlags &= ~SF_Aggregate;
+        sqlite3SelectPrep(pParse, pSub, 0);
+      }
+
+      sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, pSublist->nExpr);
+    }else{
+      sqlite3SelectDelete(db, pSub);
+    }
+    if( db->mallocFailed ) rc = SQLITE_NOMEM;
+  }
+
+  return rc;
+}
+
+/*
+** Free the Window object passed as the second argument.
+*/
+SQLITE_PRIVATE void sqlite3WindowDelete(sqlite3 *db, Window *p){
+  if( p ){
+    sqlite3ExprDelete(db, p->pFilter);
+    sqlite3ExprListDelete(db, p->pPartition);
+    sqlite3ExprListDelete(db, p->pOrderBy);
+    sqlite3ExprDelete(db, p->pEnd);
+    sqlite3ExprDelete(db, p->pStart);
+    sqlite3DbFree(db, p->zName);
+    sqlite3DbFree(db, p);
+  }
+}
+
+/*
+** Free the linked list of Window objects starting at the second argument.
+*/
+SQLITE_PRIVATE void sqlite3WindowListDelete(sqlite3 *db, Window *p){
+  while( p ){
+    Window *pNext = p->pNextWin;
+    sqlite3WindowDelete(db, p);
+    p = pNext;
+  }
+}
+
+/*
+** The argument expression is an PRECEDING or FOLLOWING offset.  The
+** value should be a non-negative integer.  If the value is not a
+** constant, change it to NULL.  The fact that it is then a non-negative
+** integer will be caught later.  But it is important not to leave
+** variable values in the expression tree.
+*/
+static Expr *sqlite3WindowOffsetExpr(Parse *pParse, Expr *pExpr){
+  if( 0==sqlite3ExprIsConstant(pExpr) ){
+    sqlite3ExprDelete(pParse->db, pExpr);
+    pExpr = sqlite3ExprAlloc(pParse->db, TK_NULL, 0, 0);
+  }
+  return pExpr;
+}
+
+/*
+** Allocate and return a new Window object describing a Window Definition.
+*/
+SQLITE_PRIVATE Window *sqlite3WindowAlloc(
+  Parse *pParse,    /* Parsing context */
+  int eType,        /* Frame type. TK_RANGE or TK_ROWS */
+  int eStart,       /* Start type: CURRENT, PRECEDING, FOLLOWING, UNBOUNDED */
+  Expr *pStart,     /* Start window size if TK_PRECEDING or FOLLOWING */
+  int eEnd,         /* End type: CURRENT, FOLLOWING, TK_UNBOUNDED, PRECEDING */
+  Expr *pEnd        /* End window size if TK_FOLLOWING or PRECEDING */
+){
+  Window *pWin = 0;
+
+  /* Parser assures the following: */
+  assert( eType==TK_RANGE || eType==TK_ROWS );
+  assert( eStart==TK_CURRENT || eStart==TK_PRECEDING
+           || eStart==TK_UNBOUNDED || eStart==TK_FOLLOWING );
+  assert( eEnd==TK_CURRENT || eEnd==TK_FOLLOWING
+           || eEnd==TK_UNBOUNDED || eEnd==TK_PRECEDING );
+  assert( (eStart==TK_PRECEDING || eStart==TK_FOLLOWING)==(pStart!=0) );
+  assert( (eEnd==TK_FOLLOWING || eEnd==TK_PRECEDING)==(pEnd!=0) );
+
+
+  /* If a frame is declared "RANGE" (not "ROWS"), then it may not use
+  ** either "<expr> PRECEDING" or "<expr> FOLLOWING".
+  */
+  if( eType==TK_RANGE && (pStart!=0 || pEnd!=0) ){
+    sqlite3ErrorMsg(pParse, "RANGE must use only UNBOUNDED or CURRENT ROW");
+    goto windowAllocErr;
+  }
+
+  /* Additionally, the
+  ** starting boundary type may not occur earlier in the following list than
+  ** the ending boundary type:
+  **
+  **   UNBOUNDED PRECEDING
+  **   <expr> PRECEDING
+  **   CURRENT ROW
+  **   <expr> FOLLOWING
+  **   UNBOUNDED FOLLOWING
+  **
+  ** The parser ensures that "UNBOUNDED PRECEDING" cannot be used as an ending
+  ** boundary, and than "UNBOUNDED FOLLOWING" cannot be used as a starting
+  ** frame boundary.
+  */
+  if( (eStart==TK_CURRENT && eEnd==TK_PRECEDING)
+   || (eStart==TK_FOLLOWING && (eEnd==TK_PRECEDING || eEnd==TK_CURRENT))
+  ){
+    sqlite3ErrorMsg(pParse, "unsupported frame delimiter for ROWS");
+    goto windowAllocErr;
+  }
+
+  pWin = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
+  if( pWin==0 ) goto windowAllocErr;
+  pWin->eType = eType;
+  pWin->eStart = eStart;
+  pWin->eEnd = eEnd;
+  pWin->pEnd = sqlite3WindowOffsetExpr(pParse, pEnd);
+  pWin->pStart = sqlite3WindowOffsetExpr(pParse, pStart);
+  return pWin;
+
+windowAllocErr:
+  sqlite3ExprDelete(pParse->db, pEnd);
+  sqlite3ExprDelete(pParse->db, pStart);
+  return 0;
+}
+
+/*
+** Attach window object pWin to expression p.
+*/
+SQLITE_PRIVATE void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){
+  if( p ){
+    /* This routine is only called for the parser.  If pWin was not
+    ** allocated due to an OOM, then the parser would fail before ever
+    ** invoking this routine */
+    if( ALWAYS(pWin) ){
+      p->pWin = pWin;
+      pWin->pOwner = p;
+      if( p->flags & EP_Distinct ){
+        sqlite3ErrorMsg(pParse,
+           "DISTINCT is not supported for window functions");
+      }
+    }
+  }else{
+    sqlite3WindowDelete(pParse->db, pWin);
+  }
+}
+
+/*
+** Return 0 if the two window objects are identical, or non-zero otherwise.
+** Identical window objects can be processed in a single scan.
+*/
+SQLITE_PRIVATE int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2){
+  if( p1->eType!=p2->eType ) return 1;
+  if( p1->eStart!=p2->eStart ) return 1;
+  if( p1->eEnd!=p2->eEnd ) return 1;
+  if( sqlite3ExprCompare(pParse, p1->pStart, p2->pStart, -1) ) return 1;
+  if( sqlite3ExprCompare(pParse, p1->pEnd, p2->pEnd, -1) ) return 1;
+  if( sqlite3ExprListCompare(p1->pPartition, p2->pPartition, -1) ) return 1;
+  if( sqlite3ExprListCompare(p1->pOrderBy, p2->pOrderBy, -1) ) return 1;
+  return 0;
+}
+
+
+/*
+** This is called by code in select.c before it calls sqlite3WhereBegin()
+** to begin iterating through the sub-query results. It is used to allocate
+** and initialize registers and cursors used by sqlite3WindowCodeStep().
+*/
+SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){
+  Window *pWin;
+  Vdbe *v = sqlite3GetVdbe(pParse);
+  int nPart = (pMWin->pPartition ? pMWin->pPartition->nExpr : 0);
+  nPart += (pMWin->pOrderBy ? pMWin->pOrderBy->nExpr : 0);
+  if( nPart ){
+    pMWin->regPart = pParse->nMem+1;
+    pParse->nMem += nPart;
+    sqlite3VdbeAddOp3(v, OP_Null, 0, pMWin->regPart, pMWin->regPart+nPart-1);
+  }
+
+  for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
+    FuncDef *p = pWin->pFunc;
+    if( (p->funcFlags & SQLITE_FUNC_MINMAX) && pWin->eStart!=TK_UNBOUNDED ){
+      /* The inline versions of min() and max() require a single ephemeral
+      ** table and 3 registers. The registers are used as follows:
+      **
+      **   regApp+0: slot to copy min()/max() argument to for MakeRecord
+      **   regApp+1: integer value used to ensure keys are unique
+      **   regApp+2: output of MakeRecord
+      */
+      ExprList *pList = pWin->pOwner->x.pList;
+      KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pList, 0, 0);
+      pWin->csrApp = pParse->nTab++;
+      pWin->regApp = pParse->nMem+1;
+      pParse->nMem += 3;
+      if( pKeyInfo && pWin->pFunc->zName[1]=='i' ){
+        assert( pKeyInfo->aSortOrder[0]==0 );
+        pKeyInfo->aSortOrder[0] = 1;
+      }
+      sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pWin->csrApp, 2);
+      sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO);
+      sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1);
+    }
+    else if( p->zName==nth_valueName || p->zName==first_valueName ){
+      /* Allocate two registers at pWin->regApp. These will be used to
+      ** store the start and end index of the current frame.  */
+      assert( pMWin->iEphCsr );
+      pWin->regApp = pParse->nMem+1;
+      pWin->csrApp = pParse->nTab++;
+      pParse->nMem += 2;
+      sqlite3VdbeAddOp2(v, OP_OpenDup, pWin->csrApp, pMWin->iEphCsr);
+    }
+    else if( p->zName==leadName || p->zName==lagName ){
+      assert( pMWin->iEphCsr );
+      pWin->csrApp = pParse->nTab++;
+      sqlite3VdbeAddOp2(v, OP_OpenDup, pWin->csrApp, pMWin->iEphCsr);
+    }
+  }
+}
+
+/*
+** A "PRECEDING <expr>" (eCond==0) or "FOLLOWING <expr>" (eCond==1) or the
+** value of the second argument to nth_value() (eCond==2) has just been
+** evaluated and the result left in register reg. This function generates VM
+** code to check that the value is a non-negative integer and throws an
+** exception if it is not.
+*/
+static void windowCheckIntValue(Parse *pParse, int reg, int eCond){
+  static const char *azErr[] = {
+    "frame starting offset must be a non-negative integer",
+    "frame ending offset must be a non-negative integer",
+    "second argument to nth_value must be a positive integer"
+  };
+  static int aOp[] = { OP_Ge, OP_Ge, OP_Gt };
+  Vdbe *v = sqlite3GetVdbe(pParse);
+  int regZero = sqlite3GetTempReg(pParse);
+  assert( eCond==0 || eCond==1 || eCond==2 );
+  sqlite3VdbeAddOp2(v, OP_Integer, 0, regZero);
+  sqlite3VdbeAddOp2(v, OP_MustBeInt, reg, sqlite3VdbeCurrentAddr(v)+2);
+  VdbeCoverageIf(v, eCond==0);
+  VdbeCoverageIf(v, eCond==1);
+  VdbeCoverageIf(v, eCond==2);
+  sqlite3VdbeAddOp3(v, aOp[eCond], regZero, sqlite3VdbeCurrentAddr(v)+2, reg);
+  VdbeCoverageNeverNullIf(v, eCond==0);
+  VdbeCoverageNeverNullIf(v, eCond==1);
+  VdbeCoverageNeverNullIf(v, eCond==2);
+  sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_ERROR, OE_Abort);
+  sqlite3VdbeAppendP4(v, (void*)azErr[eCond], P4_STATIC);
+  sqlite3ReleaseTempReg(pParse, regZero);
+}
+
+/*
+** Return the number of arguments passed to the window-function associated
+** with the object passed as the only argument to this function.
+*/
+static int windowArgCount(Window *pWin){
+  ExprList *pList = pWin->pOwner->x.pList;
+  return (pList ? pList->nExpr : 0);
+}
+
+/*
+** Generate VM code to invoke either xStep() (if bInverse is 0) or 
+** xInverse (if bInverse is non-zero) for each window function in the 
+** linked list starting at pMWin. Or, for built-in window functions
+** that do not use the standard function API, generate the required
+** inline VM code.
+**
+** If argument csr is greater than or equal to 0, then argument reg is
+** the first register in an array of registers guaranteed to be large
+** enough to hold the array of arguments for each function. In this case
+** the arguments are extracted from the current row of csr into the
+** array of registers before invoking OP_AggStep or OP_AggInverse
+**
+** Or, if csr is less than zero, then the array of registers at reg is
+** already populated with all columns from the current row of the sub-query.
+**
+** If argument regPartSize is non-zero, then it is a register containing the
+** number of rows in the current partition.
+*/
+static void windowAggStep(
+  Parse *pParse, 
+  Window *pMWin,                  /* Linked list of window functions */
+  int csr,                        /* Read arguments from this cursor */
+  int bInverse,                   /* True to invoke xInverse instead of xStep */
+  int reg,                        /* Array of registers */
+  int regPartSize                 /* Register containing size of partition */
+){
+  Vdbe *v = sqlite3GetVdbe(pParse);
+  Window *pWin;
+  for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
+    int flags = pWin->pFunc->funcFlags;
+    int regArg;
+    int nArg = windowArgCount(pWin);
+
+    if( csr>=0 ){
+      int i;
+      for(i=0; i<nArg; i++){
+        sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+i, reg+i);
+      }
+      regArg = reg;
+      if( flags & SQLITE_FUNC_WINDOW_SIZE ){
+        if( nArg==0 ){
+          regArg = regPartSize;
+        }else{
+          sqlite3VdbeAddOp2(v, OP_SCopy, regPartSize, reg+nArg);
+        }
+        nArg++;
+      }
+    }else{
+      assert( !(flags & SQLITE_FUNC_WINDOW_SIZE) );
+      regArg = reg + pWin->iArgCol;
+    }
+
+    if( (pWin->pFunc->funcFlags & SQLITE_FUNC_MINMAX) 
+      && pWin->eStart!=TK_UNBOUNDED 
+    ){
+      int addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regArg);
+      VdbeCoverage(v);
+      if( bInverse==0 ){
+        sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1, 1);
+        sqlite3VdbeAddOp2(v, OP_SCopy, regArg, pWin->regApp);
+        sqlite3VdbeAddOp3(v, OP_MakeRecord, pWin->regApp, 2, pWin->regApp+2);
+        sqlite3VdbeAddOp2(v, OP_IdxInsert, pWin->csrApp, pWin->regApp+2);
+      }else{
+        sqlite3VdbeAddOp4Int(v, OP_SeekGE, pWin->csrApp, 0, regArg, 1);
+        VdbeCoverageNeverTaken(v);
+        sqlite3VdbeAddOp1(v, OP_Delete, pWin->csrApp);
+        sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
+      }
+      sqlite3VdbeJumpHere(v, addrIsNull);
+    }else if( pWin->regApp ){
+      assert( pWin->pFunc->zName==nth_valueName
+           || pWin->pFunc->zName==first_valueName
+      );
+      assert( bInverse==0 || bInverse==1 );
+      sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1-bInverse, 1);
+    }else if( pWin->pFunc->zName==leadName
+           || pWin->pFunc->zName==lagName
+    ){
+      /* no-op */
+    }else{
+      int addrIf = 0;
+      if( pWin->pFilter ){
+        int regTmp;
+        assert( nArg==0 || nArg==pWin->pOwner->x.pList->nExpr );
+        assert( nArg || pWin->pOwner->x.pList==0 );
+        if( csr>0 ){
+          regTmp = sqlite3GetTempReg(pParse);
+          sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp);
+        }else{
+          regTmp = regArg + nArg;
+        }
+        addrIf = sqlite3VdbeAddOp3(v, OP_IfNot, regTmp, 0, 1);
+        VdbeCoverage(v);
+        if( csr>0 ){
+          sqlite3ReleaseTempReg(pParse, regTmp);
+        }
+      }
+      if( pWin->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
+        CollSeq *pColl;
+        assert( nArg>0 );
+        pColl = sqlite3ExprNNCollSeq(pParse, pWin->pOwner->x.pList->a[0].pExpr);
+        sqlite3VdbeAddOp4(v, OP_CollSeq, 0,0,0, (const char*)pColl, P4_COLLSEQ);
+      }
+      sqlite3VdbeAddOp3(v, bInverse? OP_AggInverse : OP_AggStep, 
+                        bInverse, regArg, pWin->regAccum);
+      sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
+      sqlite3VdbeChangeP5(v, (u8)nArg);
+      if( addrIf ) sqlite3VdbeJumpHere(v, addrIf);
+    }
+  }
+}
+
+/*
+** Generate VM code to invoke either xValue() (bFinal==0) or xFinalize()
+** (bFinal==1) for each window function in the linked list starting at
+** pMWin. Or, for built-in window-functions that do not use the standard
+** API, generate the equivalent VM code.
+*/
+static void windowAggFinal(Parse *pParse, Window *pMWin, int bFinal){
+  Vdbe *v = sqlite3GetVdbe(pParse);
+  Window *pWin;
+
+  for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
+    if( (pWin->pFunc->funcFlags & SQLITE_FUNC_MINMAX) 
+     && pWin->eStart!=TK_UNBOUNDED 
+    ){
+      sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult);
+      sqlite3VdbeAddOp1(v, OP_Last, pWin->csrApp);
+      VdbeCoverage(v);
+      sqlite3VdbeAddOp3(v, OP_Column, pWin->csrApp, 0, pWin->regResult);
+      sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
+      if( bFinal ){
+        sqlite3VdbeAddOp1(v, OP_ResetSorter, pWin->csrApp);
+      }
+    }else if( pWin->regApp ){
+    }else{
+      if( bFinal ){
+        sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, windowArgCount(pWin));
+        sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
+        sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult);
+        sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum);
+      }else{
+        sqlite3VdbeAddOp3(v, OP_AggValue, pWin->regAccum, windowArgCount(pWin),
+                             pWin->regResult);
+        sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
+      }
+    }
+  }
+}
+
+/*
+** This function generates VM code to invoke the sub-routine at address
+** lblFlushPart once for each partition with the entire partition cached in
+** the Window.iEphCsr temp table.
+*/
+static void windowPartitionCache(
+  Parse *pParse,
+  Select *p,                      /* The rewritten SELECT statement */
+  WhereInfo *pWInfo,              /* WhereInfo to call WhereEnd() on */
+  int regFlushPart,               /* Register to use with Gosub lblFlushPart */
+  int lblFlushPart,               /* Subroutine to Gosub to */
+  int *pRegSize                   /* OUT: Register containing partition size */
+){
+  Window *pMWin = p->pWin;
+  Vdbe *v = sqlite3GetVdbe(pParse);
+  int iSubCsr = p->pSrc->a[0].iCursor;
+  int nSub = p->pSrc->a[0].pTab->nCol;
+  int k;
+
+  int reg = pParse->nMem+1;
+  int regRecord = reg+nSub;
+  int regRowid = regRecord+1;
+
+  *pRegSize = regRowid;
+  pParse->nMem += nSub + 2;
+
+  /* Load the column values for the row returned by the sub-select
+  ** into an array of registers starting at reg. */
+  for(k=0; k<nSub; k++){
+    sqlite3VdbeAddOp3(v, OP_Column, iSubCsr, k, reg+k);
+  }
+  sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, nSub, regRecord);
+
+  /* Check if this is the start of a new partition. If so, call the
+  ** flush_partition sub-routine.  */
+  if( pMWin->pPartition ){
+    int addr;
+    ExprList *pPart = pMWin->pPartition;
+    int nPart = pPart->nExpr;
+    int regNewPart = reg + pMWin->nBufferCol;
+    KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0);
+
+    addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart);
+    sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
+    sqlite3VdbeAddOp3(v, OP_Jump, addr+2, addr+4, addr+2);
+    VdbeCoverageEqNe(v);
+    sqlite3VdbeAddOp3(v, OP_Copy, regNewPart, pMWin->regPart, nPart-1);
+    sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, lblFlushPart);
+    VdbeComment((v, "call flush_partition"));
+  }
+
+  /* Buffer the current row in the ephemeral table. */
+  sqlite3VdbeAddOp2(v, OP_NewRowid, pMWin->iEphCsr, regRowid);
+  sqlite3VdbeAddOp3(v, OP_Insert, pMWin->iEphCsr, regRecord, regRowid);
+
+  /* End of the input loop */
+  sqlite3WhereEnd(pWInfo);
+
+  /* Invoke "flush_partition" to deal with the final (or only) partition */
+  sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, lblFlushPart);
+  VdbeComment((v, "call flush_partition"));
+}
+
+/*
+** Invoke the sub-routine at regGosub (generated by code in select.c) to
+** return the current row of Window.iEphCsr. If all window functions are
+** aggregate window functions that use the standard API, a single
+** OP_Gosub instruction is all that this routine generates. Extra VM code
+** for per-row processing is only generated for the following built-in window
+** functions:
+**
+**   nth_value()
+**   first_value()
+**   lag()
+**   lead()
+*/
+static void windowReturnOneRow(
+  Parse *pParse,
+  Window *pMWin,
+  int regGosub,
+  int addrGosub
+){
+  Vdbe *v = sqlite3GetVdbe(pParse);
+  Window *pWin;
+  for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
+    FuncDef *pFunc = pWin->pFunc;
+    if( pFunc->zName==nth_valueName
+     || pFunc->zName==first_valueName
+    ){
+      int csr = pWin->csrApp;
+      int lbl = sqlite3VdbeMakeLabel(v);
+      int tmpReg = sqlite3GetTempReg(pParse);
+      sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult);
+
+      if( pFunc->zName==nth_valueName ){
+        sqlite3VdbeAddOp3(v, OP_Column, pMWin->iEphCsr, pWin->iArgCol+1,tmpReg);
+        windowCheckIntValue(pParse, tmpReg, 2);
+      }else{
+        sqlite3VdbeAddOp2(v, OP_Integer, 1, tmpReg);
+      }
+      sqlite3VdbeAddOp3(v, OP_Add, tmpReg, pWin->regApp, tmpReg);
+      sqlite3VdbeAddOp3(v, OP_Gt, pWin->regApp+1, lbl, tmpReg);
+      VdbeCoverageNeverNull(v);
+      sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, 0, tmpReg);
+      VdbeCoverageNeverTaken(v);
+      sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult);
+      sqlite3VdbeResolveLabel(v, lbl);
+      sqlite3ReleaseTempReg(pParse, tmpReg);
+    }
+    else if( pFunc->zName==leadName || pFunc->zName==lagName ){
+      int nArg = pWin->pOwner->x.pList->nExpr;
+      int iEph = pMWin->iEphCsr;
+      int csr = pWin->csrApp;
+      int lbl = sqlite3VdbeMakeLabel(v);
+      int tmpReg = sqlite3GetTempReg(pParse);
+
+      if( nArg<3 ){
+        sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult);
+      }else{
+        sqlite3VdbeAddOp3(v, OP_Column, iEph, pWin->iArgCol+2, pWin->regResult);
+      }
+      sqlite3VdbeAddOp2(v, OP_Rowid, iEph, tmpReg);
+      if( nArg<2 ){
+        int val = (pFunc->zName==leadName ? 1 : -1);
+        sqlite3VdbeAddOp2(v, OP_AddImm, tmpReg, val);
+      }else{
+        int op = (pFunc->zName==leadName ? OP_Add : OP_Subtract);
+        int tmpReg2 = sqlite3GetTempReg(pParse);
+        sqlite3VdbeAddOp3(v, OP_Column, iEph, pWin->iArgCol+1, tmpReg2);
+        sqlite3VdbeAddOp3(v, op, tmpReg2, tmpReg, tmpReg);
+        sqlite3ReleaseTempReg(pParse, tmpReg2);
+      }
+
+      sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, lbl, tmpReg);
+      VdbeCoverage(v);
+      sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult);
+      sqlite3VdbeResolveLabel(v, lbl);
+      sqlite3ReleaseTempReg(pParse, tmpReg);
+    }
+  }
+  sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub);
+}
+
+/*
+** Invoke the code generated by windowReturnOneRow() and, optionally, the
+** xInverse() function for each window function, for one or more rows
+** from the Window.iEphCsr temp table. This routine generates VM code
+** similar to:
+**
+**   while( regCtr>0 ){
+**     regCtr--;
+**     windowReturnOneRow()
+**     if( bInverse ){
+**       AggInverse
+**     }
+**     Next (Window.iEphCsr)
+**   }
+*/
+static void windowReturnRows(
+  Parse *pParse,
+  Window *pMWin,                  /* List of window functions */
+  int regCtr,                     /* Register containing number of rows */
+  int regGosub,                   /* Register for Gosub addrGosub */
+  int addrGosub,                  /* Address of sub-routine for ReturnOneRow */
+  int regInvArg,                  /* Array of registers for xInverse args */
+  int regInvSize                  /* Register containing size of partition */
+){
+  int addr;
+  Vdbe *v = sqlite3GetVdbe(pParse);
+  windowAggFinal(pParse, pMWin, 0);
+  addr = sqlite3VdbeAddOp3(v, OP_IfPos, regCtr, sqlite3VdbeCurrentAddr(v)+2 ,1);
+  VdbeCoverage(v);
+  sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
+  windowReturnOneRow(pParse, pMWin, regGosub, addrGosub);
+  if( regInvArg ){
+    windowAggStep(pParse, pMWin, pMWin->iEphCsr, 1, regInvArg, regInvSize);
+  }
+  sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, addr);
+  VdbeCoverage(v);
+  sqlite3VdbeJumpHere(v, addr+1);   /* The OP_Goto */
+}
+
+/*
+** Generate code to set the accumulator register for each window function
+** in the linked list passed as the second argument to NULL. And perform
+** any equivalent initialization required by any built-in window functions
+** in the list.
+*/
+static int windowInitAccum(Parse *pParse, Window *pMWin){
+  Vdbe *v = sqlite3GetVdbe(pParse);
+  int regArg;
+  int nArg = 0;
+  Window *pWin;
+  for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
+    FuncDef *pFunc = pWin->pFunc;
+    sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum);
+    nArg = MAX(nArg, windowArgCount(pWin));
+    if( pFunc->zName==nth_valueName
+     || pFunc->zName==first_valueName
+    ){
+      sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp);
+      sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1);
+    }
+
+    if( (pFunc->funcFlags & SQLITE_FUNC_MINMAX) && pWin->csrApp ){
+      assert( pWin->eStart!=TK_UNBOUNDED );
+      sqlite3VdbeAddOp1(v, OP_ResetSorter, pWin->csrApp);
+      sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1);
+    }
+  }
+  regArg = pParse->nMem+1;
+  pParse->nMem += nArg;
+  return regArg;
+}
+
+
+/*
+** This function does the work of sqlite3WindowCodeStep() for all "ROWS"
+** window frame types except for "BETWEEN UNBOUNDED PRECEDING AND CURRENT
+** ROW". Pseudo-code for each follows.
+**
+** ROWS BETWEEN <expr1> PRECEDING AND <expr2> FOLLOWING
+**
+**     ...
+**       if( new partition ){
+**         Gosub flush_partition
+**       }
+**       Insert (record in eph-table)
+**     sqlite3WhereEnd()
+**     Gosub flush_partition
+**  
+**   flush_partition:
+**     Once {
+**       OpenDup (iEphCsr -> csrStart)
+**       OpenDup (iEphCsr -> csrEnd)
+**     }
+**     regStart = <expr1>                // PRECEDING expression
+**     regEnd = <expr2>                  // FOLLOWING expression
+**     if( regStart<0 || regEnd<0 ){ error! }
+**     Rewind (csr,csrStart,csrEnd)      // if EOF goto flush_partition_done
+**       Next(csrEnd)                    // if EOF skip Aggstep
+**       Aggstep (csrEnd)
+**       if( (regEnd--)<=0 ){
+**         AggFinal (xValue)
+**         Gosub addrGosub
+**         Next(csr)                // if EOF goto flush_partition_done
+**         if( (regStart--)<=0 ){
+**           AggInverse (csrStart)
+**           Next(csrStart)
+**         }
+**       }
+**   flush_partition_done:
+**     ResetSorter (csr)
+**     Return
+**
+** ROWS BETWEEN <expr> PRECEDING    AND CURRENT ROW
+** ROWS BETWEEN CURRENT ROW         AND <expr> FOLLOWING
+** ROWS BETWEEN UNBOUNDED PRECEDING AND <expr> FOLLOWING
+**
+**   These are similar to the above. For "CURRENT ROW", intialize the
+**   register to 0. For "UNBOUNDED PRECEDING" to infinity.
+**
+** ROWS BETWEEN <expr> PRECEDING    AND UNBOUNDED FOLLOWING
+** ROWS BETWEEN CURRENT ROW         AND UNBOUNDED FOLLOWING
+**
+**     Rewind (csr,csrStart,csrEnd)    // if EOF goto flush_partition_done
+**     while( 1 ){
+**       Next(csrEnd)                  // Exit while(1) at EOF
+**       Aggstep (csrEnd)
+**     }
+**     while( 1 ){
+**       AggFinal (xValue)
+**       Gosub addrGosub
+**       Next(csr)                     // if EOF goto flush_partition_done
+**       if( (regStart--)<=0 ){
+**         AggInverse (csrStart)
+**         Next(csrStart)
+**       }
+**     }
+**
+**   For the "CURRENT ROW AND UNBOUNDED FOLLOWING" case, the final if() 
+**   condition is always true (as if regStart were initialized to 0).
+**
+** RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
+** 
+**   This is the only RANGE case handled by this routine. It modifies the
+**   second while( 1 ) loop in "ROWS BETWEEN CURRENT ... UNBOUNDED..." to
+**   be:
+**
+**     while( 1 ){
+**       AggFinal (xValue)
+**       while( 1 ){
+**         regPeer++
+**         Gosub addrGosub
+**         Next(csr)                     // if EOF goto flush_partition_done
+**         if( new peer ) break;
+**       }
+**       while( (regPeer--)>0 ){
+**         AggInverse (csrStart)
+**         Next(csrStart)
+**       }
+**     }
+**
+** ROWS BETWEEN <expr> FOLLOWING    AND <expr> FOLLOWING
+**
+**   regEnd = regEnd - regStart
+**   Rewind (csr,csrStart,csrEnd)   // if EOF goto flush_partition_done
+**     Aggstep (csrEnd)
+**     Next(csrEnd)                 // if EOF fall-through
+**     if( (regEnd--)<=0 ){
+**       if( (regStart--)<=0 ){
+**         AggFinal (xValue)
+**         Gosub addrGosub
+**         Next(csr)              // if EOF goto flush_partition_done
+**       }
+**       AggInverse (csrStart)
+**       Next (csrStart)
+**     }
+**
+** ROWS BETWEEN <expr> PRECEDING    AND <expr> PRECEDING
+**
+**   Replace the bit after "Rewind" in the above with:
+**
+**     if( (regEnd--)<=0 ){
+**       AggStep (csrEnd)
+**       Next (csrEnd)
+**     }
+**     AggFinal (xValue)
+**     Gosub addrGosub
+**     Next(csr)                  // if EOF goto flush_partition_done
+**     if( (regStart--)<=0 ){
+**       AggInverse (csr2)
+**       Next (csr2)
+**     }
+**
+*/
+static void windowCodeRowExprStep(
+  Parse *pParse, 
+  Select *p,
+  WhereInfo *pWInfo,
+  int regGosub, 
+  int addrGosub
+){
+  Window *pMWin = p->pWin;
+  Vdbe *v = sqlite3GetVdbe(pParse);
+  int regFlushPart;               /* Register for "Gosub flush_partition" */
+  int lblFlushPart;               /* Label for "Gosub flush_partition" */
+  int lblFlushDone;               /* Label for "Gosub flush_partition_done" */
+
+  int regArg;
+  int addr;
+  int csrStart = pParse->nTab++;
+  int csrEnd = pParse->nTab++;
+  int regStart;                    /* Value of <expr> PRECEDING */
+  int regEnd;                      /* Value of <expr> FOLLOWING */
+  int addrGoto;
+  int addrTop;
+  int addrIfPos1 = 0;
+  int addrIfPos2 = 0;
+  int regSize = 0;
+
+  assert( pMWin->eStart==TK_PRECEDING 
+       || pMWin->eStart==TK_CURRENT 
+       || pMWin->eStart==TK_FOLLOWING 
+       || pMWin->eStart==TK_UNBOUNDED 
+  );
+  assert( pMWin->eEnd==TK_FOLLOWING 
+       || pMWin->eEnd==TK_CURRENT 
+       || pMWin->eEnd==TK_UNBOUNDED 
+       || pMWin->eEnd==TK_PRECEDING 
+  );
+
+  /* Allocate register and label for the "flush_partition" sub-routine. */
+  regFlushPart = ++pParse->nMem;
+  lblFlushPart = sqlite3VdbeMakeLabel(v);
+  lblFlushDone = sqlite3VdbeMakeLabel(v);
+
+  regStart = ++pParse->nMem;
+  regEnd = ++pParse->nMem;
+
+  windowPartitionCache(pParse, p, pWInfo, regFlushPart, lblFlushPart, &regSize);
+
+  addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
+
+  /* Start of "flush_partition" */
+  sqlite3VdbeResolveLabel(v, lblFlushPart);
+  sqlite3VdbeAddOp2(v, OP_Once, 0, sqlite3VdbeCurrentAddr(v)+3);
+  VdbeCoverage(v);
+  VdbeComment((v, "Flush_partition subroutine"));
+  sqlite3VdbeAddOp2(v, OP_OpenDup, csrStart, pMWin->iEphCsr);
+  sqlite3VdbeAddOp2(v, OP_OpenDup, csrEnd, pMWin->iEphCsr);
+
+  /* If either regStart or regEnd are not non-negative integers, throw 
+  ** an exception.  */
+  if( pMWin->pStart ){
+    sqlite3ExprCode(pParse, pMWin->pStart, regStart);
+    windowCheckIntValue(pParse, regStart, 0);
+  }
+  if( pMWin->pEnd ){
+    sqlite3ExprCode(pParse, pMWin->pEnd, regEnd);
+    windowCheckIntValue(pParse, regEnd, 1);
+  }
+
+  /* If this is "ROWS <expr1> FOLLOWING AND ROWS <expr2> FOLLOWING", do:
+  **
+  **   if( regEnd<regStart ){
+  **     // The frame always consists of 0 rows
+  **     regStart = regSize;
+  **   }
+  **   regEnd = regEnd - regStart;
+  */
+  if( pMWin->pEnd && pMWin->eStart==TK_FOLLOWING ){
+    assert( pMWin->pStart!=0 );
+    assert( pMWin->eEnd==TK_FOLLOWING );
+    sqlite3VdbeAddOp3(v, OP_Ge, regStart, sqlite3VdbeCurrentAddr(v)+2, regEnd);
+    VdbeCoverageNeverNull(v);
+    sqlite3VdbeAddOp2(v, OP_Copy, regSize, regStart);
+    sqlite3VdbeAddOp3(v, OP_Subtract, regStart, regEnd, regEnd);
+  }
+
+  if( pMWin->pStart && pMWin->eEnd==TK_PRECEDING ){
+    assert( pMWin->pEnd!=0 );
+    assert( pMWin->eStart==TK_PRECEDING );
+    sqlite3VdbeAddOp3(v, OP_Le, regStart, sqlite3VdbeCurrentAddr(v)+3, regEnd);
+    VdbeCoverageNeverNull(v);
+    sqlite3VdbeAddOp2(v, OP_Copy, regSize, regStart);
+    sqlite3VdbeAddOp2(v, OP_Copy, regSize, regEnd);
+  }
+
+  /* Initialize the accumulator register for each window function to NULL */
+  regArg = windowInitAccum(pParse, pMWin);
+
+  sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr, lblFlushDone);
+  VdbeCoverage(v);
+  sqlite3VdbeAddOp2(v, OP_Rewind, csrStart, lblFlushDone);
+  VdbeCoverageNeverTaken(v);
+  sqlite3VdbeChangeP5(v, 1);
+  sqlite3VdbeAddOp2(v, OP_Rewind, csrEnd, lblFlushDone);
+  VdbeCoverageNeverTaken(v);
+  sqlite3VdbeChangeP5(v, 1);
+
+  /* Invoke AggStep function for each window function using the row that
+  ** csrEnd currently points to. Or, if csrEnd is already at EOF,
+  ** do nothing.  */
+  addrTop = sqlite3VdbeCurrentAddr(v);
+  if( pMWin->eEnd==TK_PRECEDING ){
+    addrIfPos1 = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0 , 1);
+    VdbeCoverage(v);
+  }
+  sqlite3VdbeAddOp2(v, OP_Next, csrEnd, sqlite3VdbeCurrentAddr(v)+2);
+  VdbeCoverage(v);
+  addr = sqlite3VdbeAddOp0(v, OP_Goto);
+  windowAggStep(pParse, pMWin, csrEnd, 0, regArg, regSize);
+  if( pMWin->eEnd==TK_UNBOUNDED ){
+    sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop);
+    sqlite3VdbeJumpHere(v, addr);
+    addrTop = sqlite3VdbeCurrentAddr(v);
+  }else{
+    sqlite3VdbeJumpHere(v, addr);
+    if( pMWin->eEnd==TK_PRECEDING ){
+      sqlite3VdbeJumpHere(v, addrIfPos1);
+    }
+  }
+
+  if( pMWin->eEnd==TK_FOLLOWING ){
+    addrIfPos1 = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0 , 1);
+    VdbeCoverage(v);
+  }
+  if( pMWin->eStart==TK_FOLLOWING ){
+    addrIfPos2 = sqlite3VdbeAddOp3(v, OP_IfPos, regStart, 0 , 1);
+    VdbeCoverage(v);
+  }
+  windowAggFinal(pParse, pMWin, 0);
+  windowReturnOneRow(pParse, pMWin, regGosub, addrGosub);
+  sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, sqlite3VdbeCurrentAddr(v)+2);
+  VdbeCoverage(v);
+  sqlite3VdbeAddOp2(v, OP_Goto, 0, lblFlushDone);
+  if( pMWin->eStart==TK_FOLLOWING ){
+    sqlite3VdbeJumpHere(v, addrIfPos2);
+  }
+
+  if( pMWin->eStart==TK_CURRENT 
+   || pMWin->eStart==TK_PRECEDING 
+   || pMWin->eStart==TK_FOLLOWING 
+  ){
+    int lblSkipInverse = sqlite3VdbeMakeLabel(v);;
+    if( pMWin->eStart==TK_PRECEDING ){
+      sqlite3VdbeAddOp3(v, OP_IfPos, regStart, lblSkipInverse, 1);
+      VdbeCoverage(v);
+    }
+    if( pMWin->eStart==TK_FOLLOWING ){
+      sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+2);
+      VdbeCoverage(v);
+      sqlite3VdbeAddOp2(v, OP_Goto, 0, lblSkipInverse);
+    }else{
+      sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+1);
+      VdbeCoverageAlwaysTaken(v);
+    }
+    windowAggStep(pParse, pMWin, csrStart, 1, regArg, regSize);
+    sqlite3VdbeResolveLabel(v, lblSkipInverse);
+  }
+  if( pMWin->eEnd==TK_FOLLOWING ){
+    sqlite3VdbeJumpHere(v, addrIfPos1);
+  }
+  sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop);
+
+  /* flush_partition_done: */
+  sqlite3VdbeResolveLabel(v, lblFlushDone);
+  sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr);
+  sqlite3VdbeAddOp1(v, OP_Return, regFlushPart);
+  VdbeComment((v, "end flush_partition subroutine"));
+
+  /* Jump to here to skip over flush_partition */
+  sqlite3VdbeJumpHere(v, addrGoto);
+}
+
+/*
+** This function does the work of sqlite3WindowCodeStep() for cases that
+** would normally be handled by windowCodeDefaultStep() when there are
+** one or more built-in window-functions that require the entire partition
+** to be cached in a temp table before any rows can be returned. Additionally.
+** "RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING" is always handled by
+** this function.
+**
+** Pseudo-code corresponding to the VM code generated by this function
+** for each type of window follows.
+**
+** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+**
+**   flush_partition:
+**     Once {
+**       OpenDup (iEphCsr -> csrLead)
+**     }
+**     Integer ctr 0
+**     foreach row (csrLead){
+**       if( new peer ){
+**         AggFinal (xValue)
+**         for(i=0; i<ctr; i++){
+**           Gosub addrGosub
+**           Next iEphCsr
+**         }
+**         Integer ctr 0
+**       }
+**       AggStep (csrLead)
+**       Incr ctr
+**     }
+**
+**     AggFinal (xFinalize)
+**     for(i=0; i<ctr; i++){
+**       Gosub addrGosub
+**       Next iEphCsr
+**     }
+**
+**     ResetSorter (csr)
+**     Return
+**
+** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+**
+**   As above, except that the "if( new peer )" branch is always taken.
+**
+** RANGE BETWEEN CURRENT ROW AND CURRENT ROW 
+**
+**   As above, except that each of the for() loops becomes:
+**
+**         for(i=0; i<ctr; i++){
+**           Gosub addrGosub
+**           AggInverse (iEphCsr)
+**           Next iEphCsr
+**         }
+**
+** RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
+**
+**   flush_partition:
+**     Once {
+**       OpenDup (iEphCsr -> csrLead)
+**     }
+**     foreach row (csrLead) {
+**       AggStep (csrLead)
+**     }
+**     foreach row (iEphCsr) {
+**       Gosub addrGosub
+**     }
+** 
+** RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
+**
+**   flush_partition:
+**     Once {
+**       OpenDup (iEphCsr -> csrLead)
+**     }
+**     foreach row (csrLead){
+**       AggStep (csrLead)
+**     }
+**     Rewind (csrLead)
+**     Integer ctr 0
+**     foreach row (csrLead){
+**       if( new peer ){
+**         AggFinal (xValue)
+**         for(i=0; i<ctr; i++){
+**           Gosub addrGosub
+**           AggInverse (iEphCsr)
+**           Next iEphCsr
+**         }
+**         Integer ctr 0
+**       }
+**       Incr ctr
+**     }
+**
+**     AggFinal (xFinalize)
+**     for(i=0; i<ctr; i++){
+**       Gosub addrGosub
+**       Next iEphCsr
+**     }
+**
+**     ResetSorter (csr)
+**     Return
+*/
+static void windowCodeCacheStep(
+  Parse *pParse, 
+  Select *p,
+  WhereInfo *pWInfo,
+  int regGosub, 
+  int addrGosub
+){
+  Window *pMWin = p->pWin;
+  Vdbe *v = sqlite3GetVdbe(pParse);
+  int k;
+  int addr;
+  ExprList *pPart = pMWin->pPartition;
+  ExprList *pOrderBy = pMWin->pOrderBy;
+  int nPeer = pOrderBy ? pOrderBy->nExpr : 0;
+  int regNewPeer;
+
+  int addrGoto;                   /* Address of Goto used to jump flush_par.. */
+  int addrNext;                   /* Jump here for next iteration of loop */
+  int regFlushPart;
+  int lblFlushPart;
+  int csrLead;
+  int regCtr;
+  int regArg;                     /* Register array to martial function args */
+  int regSize;
+  int lblEmpty;
+  int bReverse = pMWin->pOrderBy && pMWin->eStart==TK_CURRENT 
+          && pMWin->eEnd==TK_UNBOUNDED;
+
+  assert( (pMWin->eStart==TK_UNBOUNDED && pMWin->eEnd==TK_CURRENT) 
+       || (pMWin->eStart==TK_UNBOUNDED && pMWin->eEnd==TK_UNBOUNDED) 
+       || (pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_CURRENT) 
+       || (pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_UNBOUNDED) 
+  );
+
+  lblEmpty = sqlite3VdbeMakeLabel(v);
+  regNewPeer = pParse->nMem+1;
+  pParse->nMem += nPeer;
+
+  /* Allocate register and label for the "flush_partition" sub-routine. */
+  regFlushPart = ++pParse->nMem;
+  lblFlushPart = sqlite3VdbeMakeLabel(v);
+
+  csrLead = pParse->nTab++;
+  regCtr = ++pParse->nMem;
+
+  windowPartitionCache(pParse, p, pWInfo, regFlushPart, lblFlushPart, &regSize);
+  addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
+
+  /* Start of "flush_partition" */
+  sqlite3VdbeResolveLabel(v, lblFlushPart);
+  sqlite3VdbeAddOp2(v, OP_Once, 0, sqlite3VdbeCurrentAddr(v)+2);
+  VdbeCoverage(v);
+  sqlite3VdbeAddOp2(v, OP_OpenDup, csrLead, pMWin->iEphCsr);
+
+  /* Initialize the accumulator register for each window function to NULL */
+  regArg = windowInitAccum(pParse, pMWin);
+
+  sqlite3VdbeAddOp2(v, OP_Integer, 0, regCtr);
+  sqlite3VdbeAddOp2(v, OP_Rewind, csrLead, lblEmpty);
+  VdbeCoverage(v);
+  sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr, lblEmpty);
+  VdbeCoverageNeverTaken(v);
+
+  if( bReverse ){
+    int addr2 = sqlite3VdbeCurrentAddr(v);
+    windowAggStep(pParse, pMWin, csrLead, 0, regArg, regSize);
+    sqlite3VdbeAddOp2(v, OP_Next, csrLead, addr2);
+    VdbeCoverage(v);
+    sqlite3VdbeAddOp2(v, OP_Rewind, csrLead, lblEmpty);
+    VdbeCoverageNeverTaken(v);
+  }
+  addrNext = sqlite3VdbeCurrentAddr(v);
+
+  if( pOrderBy && (pMWin->eEnd==TK_CURRENT || pMWin->eStart==TK_CURRENT) ){
+    int bCurrent = (pMWin->eStart==TK_CURRENT);
+    int addrJump = 0;             /* Address of OP_Jump below */
+    if( pMWin->eType==TK_RANGE ){
+      int iOff = pMWin->nBufferCol + (pPart ? pPart->nExpr : 0);
+      int regPeer = pMWin->regPart + (pPart ? pPart->nExpr : 0);
+      KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOrderBy, 0, 0);
+      for(k=0; k<nPeer; k++){
+        sqlite3VdbeAddOp3(v, OP_Column, csrLead, iOff+k, regNewPeer+k);
+      }
+      addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPeer, regPeer, nPeer);
+      sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
+      addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2);
+      VdbeCoverage(v);
+      sqlite3VdbeAddOp3(v, OP_Copy, regNewPeer, regPeer, nPeer-1);
+    }
+
+    windowReturnRows(pParse, pMWin, regCtr, regGosub, addrGosub, 
+        (bCurrent ? regArg : 0), (bCurrent ? regSize : 0)
+    );
+    if( addrJump ) sqlite3VdbeJumpHere(v, addrJump);
+  }
+
+  if( bReverse==0 ){
+    windowAggStep(pParse, pMWin, csrLead, 0, regArg, regSize);
+  }
+  sqlite3VdbeAddOp2(v, OP_AddImm, regCtr, 1);
+  sqlite3VdbeAddOp2(v, OP_Next, csrLead, addrNext);
+  VdbeCoverage(v);
+
+  windowReturnRows(pParse, pMWin, regCtr, regGosub, addrGosub, 0, 0);
+
+  sqlite3VdbeResolveLabel(v, lblEmpty);
+  sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr);
+  sqlite3VdbeAddOp1(v, OP_Return, regFlushPart);
+
+  /* Jump to here to skip over flush_partition */
+  sqlite3VdbeJumpHere(v, addrGoto);
+}
+
+
+/*
+** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+**
+**   ...
+**     if( new partition ){
+**       AggFinal (xFinalize)
+**       Gosub addrGosub
+**       ResetSorter eph-table
+**     }
+**     else if( new peer ){
+**       AggFinal (xValue)
+**       Gosub addrGosub
+**       ResetSorter eph-table
+**     }
+**     AggStep
+**     Insert (record into eph-table)
+**   sqlite3WhereEnd()
+**   AggFinal (xFinalize)
+**   Gosub addrGosub
+**
+** RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
+**
+**   As above, except take no action for a "new peer". Invoke
+**   the sub-routine once only for each partition.
+**
+** RANGE BETWEEN CURRENT ROW AND CURRENT ROW
+**
+**   As above, except that the "new peer" condition is handled in the
+**   same way as "new partition" (so there is no "else if" block).
+**
+** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+** 
+**   As above, except assume every row is a "new peer".
+*/
+static void windowCodeDefaultStep(
+  Parse *pParse, 
+  Select *p,
+  WhereInfo *pWInfo,
+  int regGosub, 
+  int addrGosub
+){
+  Window *pMWin = p->pWin;
+  Vdbe *v = sqlite3GetVdbe(pParse);
+  int k;
+  int iSubCsr = p->pSrc->a[0].iCursor;
+  int nSub = p->pSrc->a[0].pTab->nCol;
+  int reg = pParse->nMem+1;
+  int regRecord = reg+nSub;
+  int regRowid = regRecord+1;
+  int addr;
+  ExprList *pPart = pMWin->pPartition;
+  ExprList *pOrderBy = pMWin->pOrderBy;
+
+  assert( pMWin->eType==TK_RANGE 
+      || (pMWin->eStart==TK_UNBOUNDED && pMWin->eEnd==TK_CURRENT)
+  );
+
+  assert( (pMWin->eStart==TK_UNBOUNDED && pMWin->eEnd==TK_CURRENT)
+       || (pMWin->eStart==TK_UNBOUNDED && pMWin->eEnd==TK_UNBOUNDED)
+       || (pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_CURRENT)
+       || (pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_UNBOUNDED && !pOrderBy)
+  );
+
+  if( pMWin->eEnd==TK_UNBOUNDED ){
+    pOrderBy = 0;
+  }
+
+  pParse->nMem += nSub + 2;
+
+  /* Load the individual column values of the row returned by
+  ** the sub-select into an array of registers. */
+  for(k=0; k<nSub; k++){
+    sqlite3VdbeAddOp3(v, OP_Column, iSubCsr, k, reg+k);
+  }
+
+  /* Check if this is the start of a new partition or peer group. */
+  if( pPart || pOrderBy ){
+    int nPart = (pPart ? pPart->nExpr : 0);
+    int addrGoto = 0;
+    int addrJump = 0;
+    int nPeer = (pOrderBy ? pOrderBy->nExpr : 0);
+
+    if( pPart ){
+      int regNewPart = reg + pMWin->nBufferCol;
+      KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0);
+      addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart);
+      sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
+      addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2);
+      VdbeCoverageEqNe(v);
+      windowAggFinal(pParse, pMWin, 1);
+      if( pOrderBy ){
+        addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
+      }
+    }
+
+    if( pOrderBy ){
+      int regNewPeer = reg + pMWin->nBufferCol + nPart;
+      int regPeer = pMWin->regPart + nPart;
+
+      if( addrJump ) sqlite3VdbeJumpHere(v, addrJump);
+      if( pMWin->eType==TK_RANGE ){
+        KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOrderBy, 0, 0);
+        addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPeer, regPeer, nPeer);
+        sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
+        addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2);
+        VdbeCoverage(v);
+      }else{
+        addrJump = 0;
+      }
+      windowAggFinal(pParse, pMWin, pMWin->eStart==TK_CURRENT);
+      if( addrGoto ) sqlite3VdbeJumpHere(v, addrGoto);
+    }
+
+    sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr,sqlite3VdbeCurrentAddr(v)+3);
+    VdbeCoverage(v);
+    sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub);
+    sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, sqlite3VdbeCurrentAddr(v)-1);
+    VdbeCoverage(v);
+
+    sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr);
+    sqlite3VdbeAddOp3(
+        v, OP_Copy, reg+pMWin->nBufferCol, pMWin->regPart, nPart+nPeer-1
+    );
+
+    if( addrJump ) sqlite3VdbeJumpHere(v, addrJump);
+  }
+
+  /* Invoke step function for window functions */
+  windowAggStep(pParse, pMWin, -1, 0, reg, 0);
+
+  /* Buffer the current row in the ephemeral table. */
+  if( pMWin->nBufferCol>0 ){
+    sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, pMWin->nBufferCol, regRecord);
+  }else{
+    sqlite3VdbeAddOp2(v, OP_Blob, 0, regRecord);
+    sqlite3VdbeAppendP4(v, (void*)"", 0);
+  }
+  sqlite3VdbeAddOp2(v, OP_NewRowid, pMWin->iEphCsr, regRowid);
+  sqlite3VdbeAddOp3(v, OP_Insert, pMWin->iEphCsr, regRecord, regRowid);
+
+  /* End the database scan loop. */
+  sqlite3WhereEnd(pWInfo);
+
+  windowAggFinal(pParse, pMWin, 1);
+  sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr,sqlite3VdbeCurrentAddr(v)+3);
+  VdbeCoverage(v);
+  sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub);
+  sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, sqlite3VdbeCurrentAddr(v)-1);
+  VdbeCoverage(v);
+}
+
+/*
+** Allocate and return a duplicate of the Window object indicated by the
+** third argument. Set the Window.pOwner field of the new object to
+** pOwner.
+*/
+SQLITE_PRIVATE Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p){
+  Window *pNew = 0;
+  if( p ){
+    pNew = sqlite3DbMallocZero(db, sizeof(Window));
+    if( pNew ){
+      pNew->zName = sqlite3DbStrDup(db, p->zName);
+      pNew->pFilter = sqlite3ExprDup(db, p->pFilter, 0);
+      pNew->pPartition = sqlite3ExprListDup(db, p->pPartition, 0);
+      pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, 0);
+      pNew->eType = p->eType;
+      pNew->eEnd = p->eEnd;
+      pNew->eStart = p->eStart;
+      pNew->pStart = sqlite3ExprDup(db, p->pStart, 0);
+      pNew->pEnd = sqlite3ExprDup(db, p->pEnd, 0);
+      pNew->pOwner = pOwner;
+    }
+  }
+  return pNew;
+}
+
+/*
+** Return a copy of the linked list of Window objects passed as the
+** second argument.
+*/
+SQLITE_PRIVATE Window *sqlite3WindowListDup(sqlite3 *db, Window *p){
+  Window *pWin;
+  Window *pRet = 0;
+  Window **pp = &pRet;
+
+  for(pWin=p; pWin; pWin=pWin->pNextWin){
+    *pp = sqlite3WindowDup(db, 0, pWin);
+    if( *pp==0 ) break;
+    pp = &((*pp)->pNextWin);
+  }
+
+  return pRet;
+}
+
+/*
+** sqlite3WhereBegin() has already been called for the SELECT statement 
+** passed as the second argument when this function is invoked. It generates
+** code to populate the Window.regResult register for each window function and
+** invoke the sub-routine at instruction addrGosub once for each row.
+** This function calls sqlite3WhereEnd() before returning. 
+*/
+SQLITE_PRIVATE void sqlite3WindowCodeStep(
+  Parse *pParse,                  /* Parse context */
+  Select *p,                      /* Rewritten SELECT statement */
+  WhereInfo *pWInfo,              /* Context returned by sqlite3WhereBegin() */
+  int regGosub,                   /* Register for OP_Gosub */
+  int addrGosub                   /* OP_Gosub here to return each row */
+){
+  Window *pMWin = p->pWin;
+
+  /* There are three different functions that may be used to do the work
+  ** of this one, depending on the window frame and the specific built-in
+  ** window functions used (if any).
+  **
+  ** windowCodeRowExprStep() handles all "ROWS" window frames, except for:
+  **
+  **   ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+  **
+  ** The exception is because windowCodeRowExprStep() implements all window
+  ** frame types by caching the entire partition in a temp table, and
+  ** "ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW" is easy enough to
+  ** implement without such a cache.
+  **
+  ** windowCodeCacheStep() is used for:
+  **
+  **   RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
+  **
+  ** It is also used for anything not handled by windowCodeRowExprStep() 
+  ** that invokes a built-in window function that requires the entire 
+  ** partition to be cached in a temp table before any rows are returned
+  ** (e.g. nth_value() or percent_rank()).
+  **
+  ** Finally, assuming there is no built-in window function that requires
+  ** the partition to be cached, windowCodeDefaultStep() is used for:
+  **
+  **   RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 
+  **   RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
+  **   RANGE BETWEEN CURRENT ROW AND CURRENT ROW 
+  **   ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
+  **
+  ** windowCodeDefaultStep() is the only one of the three functions that
+  ** does not cache each partition in a temp table before beginning to
+  ** return rows.
+  */
+  if( pMWin->eType==TK_ROWS 
+   && (pMWin->eStart!=TK_UNBOUNDED||pMWin->eEnd!=TK_CURRENT||!pMWin->pOrderBy)
+  ){
+    VdbeModuleComment((pParse->pVdbe, "Begin RowExprStep()"));
+    windowCodeRowExprStep(pParse, p, pWInfo, regGosub, addrGosub);
+  }else{
+    Window *pWin;
+    int bCache = 0;               /* True to use CacheStep() */
+
+    if( pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_UNBOUNDED ){
+      bCache = 1;
+    }else{
+      for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
+        FuncDef *pFunc = pWin->pFunc;
+        if( (pFunc->funcFlags & SQLITE_FUNC_WINDOW_SIZE)
+         || (pFunc->zName==nth_valueName)
+         || (pFunc->zName==first_valueName)
+         || (pFunc->zName==leadName)
+         || (pFunc->zName==lagName)
+        ){
+          bCache = 1;
+          break;
+        }
+      }
+    }
+
+    /* Otherwise, call windowCodeDefaultStep().  */
+    if( bCache ){
+      VdbeModuleComment((pParse->pVdbe, "Begin CacheStep()"));
+      windowCodeCacheStep(pParse, p, pWInfo, regGosub, addrGosub);
+    }else{
+      VdbeModuleComment((pParse->pVdbe, "Begin DefaultStep()"));
+      windowCodeDefaultStep(pParse, p, pWInfo, regGosub, addrGosub);
+    }
+  }
+}
+
+#endif /* SQLITE_OMIT_WINDOWFUNC */
+
+/************** End of window.c **********************************************/
 /************** Begin file parse.c *******************************************/
 /*
 ** 2000-05-29
@@ -141456,6 +145962,8 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
 */
 struct TrigEvent { int a; IdList * b; };
 
+struct FrameBound     { int eType; Expr *pExpr; };
+
 /*
 ** Disable lookaside memory allocation for objects that might be
 ** shared across database connections.
@@ -141496,10 +146004,21 @@ static void disableLookaside(Parse *pParse){
   static Expr *tokenExpr(Parse *pParse, int op, Token t){
     Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1);
     if( p ){
-      memset(p, 0, sizeof(Expr));
+      /* memset(p, 0, sizeof(Expr)); */
       p->op = (u8)op;
+      p->affinity = 0;
       p->flags = EP_Leaf;
       p->iAgg = -1;
+      p->pLeft = p->pRight = 0;
+      p->x.pList = 0;
+      p->pAggInfo = 0;
+      p->pTab = 0;
+      p->op2 = 0;
+      p->iTable = 0;
+      p->iColumn = 0;
+#ifndef SQLITE_OMIT_WINDOWFUNC
+      p->pWin = 0;
+#endif
       p->u.zToken = (char*)&p[1];
       memcpy(p->u.zToken, t.z, t.n);
       p->u.zToken[t.n] = 0;
@@ -141510,15 +146029,19 @@ static void disableLookaside(Parse *pParse){
 #if SQLITE_MAX_EXPR_DEPTH>0
       p->nHeight = 1;
 #endif  
+      if( IN_RENAME_OBJECT ){
+        return (Expr*)sqlite3RenameTokenMap(pParse, (void*)p, &t);
+      }
     }
     return p;
   }
 
+
   /* 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 ){
+    if( pA && pY && pY->op==TK_NULL && !IN_RENAME_OBJECT ){
       pA->op = (u8)op;
       sqlite3ExprDelete(db, pA->pRight);
       pA->pRight = 0;
@@ -141609,26 +146132,28 @@ static void disableLookaside(Parse *pParse){
 # define INTERFACE 1
 #endif
 /************* Begin control #defines *****************************************/
-#define YYCODETYPE unsigned char
-#define YYNOCODE 255
+#define YYCODETYPE unsigned short int
+#define YYNOCODE 277
 #define YYACTIONTYPE unsigned short int
-#define YYWILDCARD 84
+#define YYWILDCARD 91
 #define sqlite3ParserTOKENTYPE Token
 typedef union {
   int yyinit;
   sqlite3ParserTOKENTYPE yy0;
-  const char* yy36;
-  TriggerStep* yy47;
-  With* yy91;
-  struct {int value; int mask;} yy107;
-  Expr* yy182;
-  Upsert* yy198;
-  ExprList* yy232;
-  struct TrigEvent yy300;
-  Select* yy399;
-  SrcList* yy427;
-  int yy502;
-  IdList* yy510;
+  Expr* yy18;
+  struct TrigEvent yy34;
+  IdList* yy48;
+  int yy70;
+  struct {int value; int mask;} yy111;
+  struct FrameBound yy119;
+  SrcList* yy135;
+  TriggerStep* yy207;
+  Window* yy327;
+  Upsert* yy340;
+  const char* yy392;
+  ExprList* yy420;
+  With* yy449;
+  Select* yy489;
 } YYMINORTYPE;
 #ifndef YYSTACKDEPTH
 #define YYSTACKDEPTH 100
@@ -141644,18 +146169,19 @@ typedef union {
 #define sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse;
 #define sqlite3ParserCTX_STORE yypParser->pParse=pParse;
 #define YYFALLBACK 1
-#define YYNSTATE             490
-#define YYNRULE              341
-#define YYNTOKEN             145
-#define YY_MAX_SHIFT         489
-#define YY_MIN_SHIFTREDUCE   705
-#define YY_MAX_SHIFTREDUCE   1045
-#define YY_ERROR_ACTION      1046
-#define YY_ACCEPT_ACTION     1047
-#define YY_NO_ACTION         1048
-#define YY_MIN_REDUCE        1049
-#define YY_MAX_REDUCE        1389
+#define YYNSTATE             521
+#define YYNRULE              367
+#define YYNTOKEN             155
+#define YY_MAX_SHIFT         520
+#define YY_MIN_SHIFTREDUCE   756
+#define YY_MAX_SHIFTREDUCE   1122
+#define YY_ERROR_ACTION      1123
+#define YY_ACCEPT_ACTION     1124
+#define YY_NO_ACTION         1125
+#define YY_MIN_REDUCE        1126
+#define YY_MAX_REDUCE        1492
 /************* End control #defines *******************************************/
+#define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])))
 
 /* Define the yytestcase() macro to be a no-op if is not already defined
 ** otherwise.
@@ -141720,503 +146246,568 @@ typedef union {
 **  yy_default[]       Default action for each state.
 **
 *********** Begin parsing tables **********************************************/
-#define YY_ACTTAB_COUNT (1657)
+#define YY_ACTTAB_COUNT (2009)
 static const YYACTIONTYPE yy_action[] = {
- /*     0 */   349,   99,   96,  185,   99,   96,  185,  233, 1047,    1,
- /*    10 */     1,  489,    2, 1051,  484,  477,  477,  477,  260,  351,
- /*    20 */   121, 1310, 1120, 1120, 1178, 1115, 1094, 1128,  380,  380,
- /*    30 */   380,  835,  454,  410, 1115,   59,   59, 1357,  425,  836,
- /*    40 */   710,  711,  712,  106,  107,   97, 1023, 1023,  900,  903,
- /*    50 */   892,  892,  104,  104,  105,  105,  105,  105,  346,  238,
- /*    60 */   238,   99,   96,  185,  238,  238,  889,  889,  901,  904,
- /*    70 */   460,  481,  351,   99,   96,  185,  481,  347, 1177,   82,
- /*    80 */   388,  214,  182,   23,  194,  103,  103,  103,  103,  102,
- /*    90 */   102,  101,  101,  101,  100,  381,  106,  107,   97, 1023,
- /*   100 */  1023,  900,  903,  892,  892,  104,  104,  105,  105,  105,
- /*   110 */   105,   10,  385,  484,   24,  484, 1333,  489,    2, 1051,
- /*   120 */   335, 1043,  108,  893,  260,  351,  121,   99,   96,  185,
- /*   130 */   100,  381,  386, 1128,   59,   59,   59,   59,  103,  103,
- /*   140 */   103,  103,  102,  102,  101,  101,  101,  100,  381,  106,
- /*   150 */   107,   97, 1023, 1023,  900,  903,  892,  892,  104,  104,
- /*   160 */   105,  105,  105,  105,  360,  238,  238,  170,  170,  467,
- /*   170 */   455,  467,  464,   67,  381,  329,  169,  481,  351,  343,
- /*   180 */   338,  400, 1044,   68,  101,  101,  101,  100,  381,  393,
- /*   190 */   194,  103,  103,  103,  103,  102,  102,  101,  101,  101,
- /*   200 */   100,  381,  106,  107,   97, 1023, 1023,  900,  903,  892,
- /*   210 */   892,  104,  104,  105,  105,  105,  105,  483,  385,  103,
- /*   220 */   103,  103,  103,  102,  102,  101,  101,  101,  100,  381,
- /*   230 */   268,  351,  946,  946,  422,  296,  102,  102,  101,  101,
- /*   240 */   101,  100,  381,  861,  103,  103,  103,  103,  102,  102,
- /*   250 */   101,  101,  101,  100,  381,  106,  107,   97, 1023, 1023,
- /*   260 */   900,  903,  892,  892,  104,  104,  105,  105,  105,  105,
- /*   270 */   484,  983, 1383,  206, 1353, 1383,  438,  435,  434,  281,
- /*   280 */   396,  269, 1089,  941,  351, 1002,  433,  861,  743,  401,
- /*   290 */   282,   57,   57,  482,  145,  791,  791,  103,  103,  103,
- /*   300 */   103,  102,  102,  101,  101,  101,  100,  381,  106,  107,
- /*   310 */    97, 1023, 1023,  900,  903,  892,  892,  104,  104,  105,
- /*   320 */   105,  105,  105,  281, 1002, 1003, 1004,  206,  879,  319,
- /*   330 */   438,  435,  434,  981,  259,  474,  360,  351, 1118, 1118,
- /*   340 */   433,  736,  379,  378,  872, 1002, 1356,  322,  871,  766,
- /*   350 */   103,  103,  103,  103,  102,  102,  101,  101,  101,  100,
- /*   360 */   381,  106,  107,   97, 1023, 1023,  900,  903,  892,  892,
- /*   370 */   104,  104,  105,  105,  105,  105,  484,  801,  484,  871,
- /*   380 */   871,  873,  401,  282, 1002, 1003, 1004, 1030,  360, 1030,
- /*   390 */   351,  983, 1384,  213,  880, 1384,  145,   59,   59,   59,
- /*   400 */    59, 1002,  244,  103,  103,  103,  103,  102,  102,  101,
- /*   410 */   101,  101,  100,  381,  106,  107,   97, 1023, 1023,  900,
- /*   420 */   903,  892,  892,  104,  104,  105,  105,  105,  105,  274,
- /*   430 */   484,  110,  467,  479,  467,  444,  259,  474,  232,  232,
- /*   440 */  1002, 1003, 1004,  351,  210,  335,  982,  866, 1385,  336,
- /*   450 */   481,   59,   59,  981,  245,  307,  103,  103,  103,  103,
- /*   460 */   102,  102,  101,  101,  101,  100,  381,  106,  107,   97,
- /*   470 */  1023, 1023,  900,  903,  892,  892,  104,  104,  105,  105,
- /*   480 */   105,  105,  453,  459,  484,  408,  377,  259,  474,  271,
- /*   490 */   183,  273,  209,  208,  207,  356,  351,  307,  178,  177,
- /*   500 */   127, 1006, 1098,   14,   14,   43,   43, 1044,  425,  103,
- /*   510 */   103,  103,  103,  102,  102,  101,  101,  101,  100,  381,
- /*   520 */   106,  107,   97, 1023, 1023,  900,  903,  892,  892,  104,
- /*   530 */   104,  105,  105,  105,  105,  294, 1132,  408,  160,  484,
- /*   540 */   408, 1006,  129,  962, 1209,  239,  239,  481,  307,  425,
- /*   550 */  1309, 1097,  351,  235,  243,  272,  820,  481,  963,  425,
- /*   560 */    11,   11,  103,  103,  103,  103,  102,  102,  101,  101,
- /*   570 */   101,  100,  381,  964,  362, 1002,  106,  107,   97, 1023,
- /*   580 */  1023,  900,  903,  892,  892,  104,  104,  105,  105,  105,
- /*   590 */   105, 1275,  161,  126,  777,  289, 1209,  292, 1072,  357,
- /*   600 */  1209, 1127,  476,  357,  778,  425,  247,  425,  351,  248,
- /*   610 */   414,  364,  414,  171, 1002, 1003, 1004,   84,  103,  103,
- /*   620 */   103,  103,  102,  102,  101,  101,  101,  100,  381, 1002,
- /*   630 */   184,  484,  106,  107,   97, 1023, 1023,  900,  903,  892,
- /*   640 */   892,  104,  104,  105,  105,  105,  105, 1123, 1209,  287,
- /*   650 */   484, 1209,   11,   11,  179,  820,  259,  474,  307,  237,
- /*   660 */   182,  351,  321,  365,  414,  308,  367,  366, 1002, 1003,
- /*   670 */  1004,   44,   44,   87,  103,  103,  103,  103,  102,  102,
- /*   680 */   101,  101,  101,  100,  381,  106,  107,   97, 1023, 1023,
- /*   690 */   900,  903,  892,  892,  104,  104,  105,  105,  105,  105,
- /*   700 */   246,  368,  280,  128,   10,  358,  146,  796,  835,  258,
- /*   710 */  1020,   88,  795,   86,  351,  421,  836,  943,  376,  348,
- /*   720 */   191,  943, 1318,  267,  308,  279,  456,  103,  103,  103,
- /*   730 */   103,  102,  102,  101,  101,  101,  100,  381,  106,   95,
- /*   740 */    97, 1023, 1023,  900,  903,  892,  892,  104,  104,  105,
- /*   750 */   105,  105,  105,  420,  249,  238,  238,  238,  238,   79,
- /*   760 */   375,  125,  305,   29,  262,  978,  351,  481,  337,  481,
- /*   770 */   756,  755,  304,  278,  415,   15,   81,  940, 1126,  940,
- /*   780 */   103,  103,  103,  103,  102,  102,  101,  101,  101,  100,
- /*   790 */   381,  107,   97, 1023, 1023,  900,  903,  892,  892,  104,
- /*   800 */   104,  105,  105,  105,  105,  457,  263,  484,  174,  484,
- /*   810 */   238,  238,  863,  407,  402,  216,  216,  351,  409,  193,
- /*   820 */   283,  216,  481,   81,  763,  764,  266,    5,   13,   13,
- /*   830 */    34,   34,  103,  103,  103,  103,  102,  102,  101,  101,
- /*   840 */   101,  100,  381,   97, 1023, 1023,  900,  903,  892,  892,
- /*   850 */   104,  104,  105,  105,  105,  105,   93,  475, 1002,    4,
- /*   860 */   403, 1002,  340,  431, 1002,  297,  212, 1277,   81,  746,
- /*   870 */  1163,  152,  926,  478,  166,  212,  757,  829,  930,  939,
- /*   880 */   216,  939,  858,  103,  103,  103,  103,  102,  102,  101,
- /*   890 */   101,  101,  100,  381,  238,  238,  382, 1002, 1003, 1004,
- /*   900 */  1002, 1003, 1004, 1002, 1003, 1004,  481,  439,  472,  746,
- /*   910 */   105,  105,  105,  105,   98,  758, 1162,  145,  930,  412,
- /*   920 */   879,  406,  793,   81,  395,   89,   90,   91,  105,  105,
- /*   930 */   105,  105, 1323,   92,  484,  382,  486,  485,  240,  275,
- /*   940 */   871,  103,  103,  103,  103,  102,  102,  101,  101,  101,
- /*   950 */   100,  381, 1096,  371,  355,   45,   45,  259,  474,  103,
- /*   960 */   103,  103,  103,  102,  102,  101,  101,  101,  100,  381,
- /*   970 */  1150,  871,  871,  873,  874,   21, 1332,  991,  384,  730,
- /*   980 */   722,  242,  123, 1298,  124,  875,  333,  333,  332,  227,
- /*   990 */   330,  991,  384,  719,  256,  242,  484,  391,  413, 1297,
- /*  1000 */   333,  333,  332,  227,  330,  748,  187,  719,  265,  470,
- /*  1010 */  1279, 1002,  484,  417,  391,  390,  264,   11,   11,  284,
- /*  1020 */   187,  732,  265,   93,  475,  875,    4, 1279, 1281,  419,
- /*  1030 */   264,  369,  416,   11,   11, 1159,  288,  484,  399, 1346,
- /*  1040 */   478,  379,  378,  291,  484,  293,  189,  250,  295, 1027,
- /*  1050 */  1002, 1003, 1004,  190, 1029, 1111,  140,  188,   11,   11,
- /*  1060 */   189,  732, 1028,  382,  923,   46,   46,  190, 1095,  230,
- /*  1070 */   140,  188,  462,   93,  475,  472,    4,  300,  309,  391,
- /*  1080 */   373,    6, 1069,  217,  739,  310, 1030,  879, 1030, 1171,
- /*  1090 */   478,  352, 1279,   90,   91,  800,  259,  474, 1208,  484,
- /*  1100 */    92, 1268,  382,  486,  485,  352, 1002,  871,  879,  426,
- /*  1110 */   259,  474,  172,  382,  238,  238, 1146,  170, 1021,  389,
- /*  1120 */    47,   47, 1157,  739,  872,  472,  481,  469,  871,  350,
- /*  1130 */  1214,   83,  475,  389,    4, 1078, 1071,  879,  871,  871,
- /*  1140 */   873,  874,   21,   90,   91, 1002, 1003, 1004,  478,  251,
- /*  1150 */    92,  251,  382,  486,  485,  443,  370,  871, 1021,  871,
- /*  1160 */   871,  873,  224,  241,  306,  441,  301,  440,  211, 1060,
- /*  1170 */   820,  382,  822,  447,  299, 1059,  484, 1061, 1143,  962,
- /*  1180 */   430,  796,  484,  472, 1340,  312,  795,  465,  871,  871,
- /*  1190 */   873,  874,   21,  314,  963,  879,  316,   59,   59, 1002,
- /*  1200 */     9,   90,   91,   48,   48,  238,  238,  210,   92,  964,
- /*  1210 */   382,  486,  485,  176,  334,  871,  242,  481, 1193,  238,
- /*  1220 */   238,  333,  333,  332,  227,  330,  394,  270,  719,  277,
- /*  1230 */   471,  481,  467,  466,  484,  145,  217, 1201, 1002, 1003,
- /*  1240 */  1004,  187,    3,  265,  184,  445,  871,  871,  873,  874,
- /*  1250 */    21,  264, 1337,  450, 1051,   39,   39,  392,  356,  260,
- /*  1260 */   342,  121,  468,  411,  436,  821,  180, 1094, 1128,  820,
- /*  1270 */   303, 1021, 1272, 1271,  299,  259,  474,  238,  238, 1002,
- /*  1280 */   473,  189,  484,  318,  327,  238,  238,  484,  190,  481,
- /*  1290 */   446,  140,  188, 1343,  238,  238, 1038,  481,  148,  175,
- /*  1300 */   238,  238,  484,   49,   49,  219,  481,  484,   35,   35,
- /*  1310 */  1317, 1021,  481,  484, 1035,  484, 1315,  484, 1002, 1003,
- /*  1320 */  1004,  484,   66,   36,   36,  194,  352,  484,   38,   38,
- /*  1330 */   484,  259,  474,   69,   50,   50,   51,   51,   52,   52,
- /*  1340 */   359,  484,   12,   12,  484, 1198,  484,  158,   53,   53,
- /*  1350 */   405,  112,  112,  385,  389,  484,   26,  484,  143,  484,
- /*  1360 */   150,  484,   54,   54,  397,   40,   40,   55,   55,  484,
- /*  1370 */    79,  484,  153, 1190,  484,  154,   56,   56,   41,   41,
- /*  1380 */    58,   58,  133,  133,  484,  398,  484,  429,  484,  155,
- /*  1390 */   134,  134,  135,  135,  484,   63,   63,  484,  341,  484,
- /*  1400 */   339,  484,  196,  484,  156,   42,   42,  113,  113,   60,
- /*  1410 */    60,  484,  404,  484,   27,  114,  114, 1204,  115,  115,
- /*  1420 */   111,  111,  132,  132,  131,  131, 1266,  418,  484,  162,
- /*  1430 */   484,  200,  119,  119,  118,  118,  484,   74,  424,  484,
- /*  1440 */  1286,  484,  231,  484,  202,  484,  167,  286,  427,  116,
- /*  1450 */   116,  117,  117,  290,  203,  442, 1062,   62,   62,  204,
- /*  1460 */    64,   64,   61,   61,   33,   33,   37,   37,  344,  372,
- /*  1470 */  1114, 1105,  748, 1113,  374, 1112,  254,  458, 1086,  255,
- /*  1480 */   345, 1085,  302, 1084, 1355,   78, 1154,  311, 1104,  449,
- /*  1490 */   452, 1155, 1153,  218,    7,  313,  315,  320, 1152,   85,
- /*  1500 */  1252,  317,  109,   80,  463,  225,  461, 1068,   25,  487,
- /*  1510 */   997,  323,  257,  226,  229,  228, 1136,  324,  325,  326,
- /*  1520 */   488,  136, 1057, 1052, 1302, 1303, 1301,  706, 1300,  137,
- /*  1530 */   122,  138,  383,  173, 1082,  261,  186,  252, 1081,   65,
- /*  1540 */   387,  120,  938,  936,  855,  353,  149, 1079,  139,  151,
- /*  1550 */   192,  780,  195,  276,  952,  157,  141,  361,   70,  363,
- /*  1560 */   859,  159,   71,   72,  142,   73,  955,  354,  147,  197,
- /*  1570 */   198,  951,  130,   16,  199,  285,  216, 1032,  201,  423,
- /*  1580 */   164,  944,  163,   28,  721,  428,  304,  165,  205,  759,
- /*  1590 */    75,  432,  298,   17,   18,  437,   76,  253,  878,  144,
- /*  1600 */   877,  906,   77,  986,   30,  448,  987,   31,  451,  181,
- /*  1610 */   234,  236,  168,  828,  823,   89,  910,  921,   81,  907,
- /*  1620 */   215,  905,  909,  961,  960,   19,  221,   20,  220,   22,
- /*  1630 */    32,  331,  876,  731,   94,  790,  794,    8,  992,  222,
- /*  1640 */   480,  328, 1048, 1048, 1048, 1048, 1048, 1048, 1048, 1048,
- /*  1650 */   223, 1048, 1048, 1048, 1048, 1348, 1347,
+ /*     0 */   368,  105,  102,  197,  105,  102,  197,  515, 1124,    1,
+ /*    10 */     1,  520,    2, 1128,  515, 1192, 1171, 1456,  275,  370,
+ /*    20 */   127, 1389, 1197, 1197, 1192, 1166,  178, 1205,   64,   64,
+ /*    30 */   477,  887,  322,  428,  348,   37,   37,  808,  362,  888,
+ /*    40 */   509,  509,  509,  112,  113,  103, 1100, 1100,  953,  956,
+ /*    50 */   946,  946,  110,  110,  111,  111,  111,  111,  365,  252,
+ /*    60 */   252,  515,  252,  252,  497,  515,  309,  515,  459,  515,
+ /*    70 */  1079,  491,  512,  478,    6,  512,  809,  134,  498,  228,
+ /*    80 */   194,  428,   37,   37,  515,  208,   64,   64,   64,   64,
+ /*    90 */    13,   13,  109,  109,  109,  109,  108,  108,  107,  107,
+ /*   100 */   107,  106,  401,  258,  381,   13,   13,  398,  397,  428,
+ /*   110 */   252,  252,  370,  476,  405, 1104, 1079, 1080, 1081,  386,
+ /*   120 */  1106,  390,  497,  512,  497, 1423, 1419,  304, 1105,  307,
+ /*   130 */  1256,  496,  370,  499,   16,   16,  112,  113,  103, 1100,
+ /*   140 */  1100,  953,  956,  946,  946,  110,  110,  111,  111,  111,
+ /*   150 */   111,  262, 1107,  495, 1107,  401,  112,  113,  103, 1100,
+ /*   160 */  1100,  953,  956,  946,  946,  110,  110,  111,  111,  111,
+ /*   170 */   111,  129, 1425,  343, 1420,  339, 1059,  492, 1057,  263,
+ /*   180 */    73,  105,  102,  197,  994,  109,  109,  109,  109,  108,
+ /*   190 */   108,  107,  107,  107,  106,  401,  370,  111,  111,  111,
+ /*   200 */   111,  104,  492,   89, 1432,  109,  109,  109,  109,  108,
+ /*   210 */   108,  107,  107,  107,  106,  401,  111,  111,  111,  111,
+ /*   220 */   112,  113,  103, 1100, 1100,  953,  956,  946,  946,  110,
+ /*   230 */   110,  111,  111,  111,  111,  109,  109,  109,  109,  108,
+ /*   240 */   108,  107,  107,  107,  106,  401,  114,  108,  108,  107,
+ /*   250 */   107,  107,  106,  401,  109,  109,  109,  109,  108,  108,
+ /*   260 */   107,  107,  107,  106,  401,  152,  399,  399,  399,  109,
+ /*   270 */   109,  109,  109,  108,  108,  107,  107,  107,  106,  401,
+ /*   280 */   178,  493, 1412,  434, 1037, 1486, 1079,  515, 1486,  370,
+ /*   290 */   421,  297,  357,  412,   74, 1079,  109,  109,  109,  109,
+ /*   300 */   108,  108,  107,  107,  107,  106,  401, 1413,   37,   37,
+ /*   310 */  1431,  274,  506,  112,  113,  103, 1100, 1100,  953,  956,
+ /*   320 */   946,  946,  110,  110,  111,  111,  111,  111, 1436,  520,
+ /*   330 */     2, 1128, 1079, 1080, 1081,  430,  275, 1079,  127,  366,
+ /*   340 */   933, 1079, 1080, 1081,  220, 1205,  913,  458,  455,  454,
+ /*   350 */   392,  167,  515, 1035,  152,  445,  924,  453,  152,  874,
+ /*   360 */   923,  289,  109,  109,  109,  109,  108,  108,  107,  107,
+ /*   370 */   107,  106,  401,   13,   13,  261,  853,  252,  252,  227,
+ /*   380 */   106,  401,  370, 1079, 1080, 1081,  311,  388, 1079,  296,
+ /*   390 */   512,  923,  923,  925,  231,  323, 1255, 1388, 1423,  490,
+ /*   400 */   274,  506,   12,  208,  274,  506,  112,  113,  103, 1100,
+ /*   410 */  1100,  953,  956,  946,  946,  110,  110,  111,  111,  111,
+ /*   420 */   111, 1440,  286, 1128,  288, 1079, 1097,  247,  275, 1098,
+ /*   430 */   127,  387,  405,  389, 1079, 1080, 1081, 1205,  159,  238,
+ /*   440 */   255,  321,  461,  316,  460,  225,  790,  105,  102,  197,
+ /*   450 */   513,  314,  842,  842,  445,  109,  109,  109,  109,  108,
+ /*   460 */   108,  107,  107,  107,  106,  401,  515,  514,  515,  252,
+ /*   470 */   252, 1079, 1080, 1081,  435,  370, 1098,  933, 1460,  794,
+ /*   480 */   274,  506,  512,  105,  102,  197,  336,   63,   63,   64,
+ /*   490 */    64,   27,  790,  924,  287,  208, 1354,  923,  515,  112,
+ /*   500 */   113,  103, 1100, 1100,  953,  956,  946,  946,  110,  110,
+ /*   510 */   111,  111,  111,  111,  107,  107,  107,  106,  401,   49,
+ /*   520 */    49,  515,   28, 1079,  405,  497,  421,  297,  923,  923,
+ /*   530 */   925,  186,  468, 1079,  467,  999,  999,  442,  515, 1079,
+ /*   540 */   334,  515,   45,   45, 1083,  342,  173,  168,  109,  109,
+ /*   550 */   109,  109,  108,  108,  107,  107,  107,  106,  401,   13,
+ /*   560 */    13,  205,   13,   13,  252,  252, 1195, 1195,  370, 1079,
+ /*   570 */  1080, 1081,  787,  265,    5,  359,  494,  512,  469, 1079,
+ /*   580 */  1080, 1081,  398,  397, 1079, 1079, 1080, 1081,    3,  282,
+ /*   590 */  1079, 1083,  112,  113,  103, 1100, 1100,  953,  956,  946,
+ /*   600 */   946,  110,  110,  111,  111,  111,  111,  252,  252, 1015,
+ /*   610 */   220, 1079,  873,  458,  455,  454,  943,  943,  954,  957,
+ /*   620 */   512,  252,  252,  453, 1016, 1079,  445, 1107, 1209, 1107,
+ /*   630 */  1079, 1080, 1081,  515,  512,  426, 1079, 1080, 1081, 1017,
+ /*   640 */   512,  109,  109,  109,  109,  108,  108,  107,  107,  107,
+ /*   650 */   106,  401, 1052,  515,   50,   50,  515, 1079, 1080, 1081,
+ /*   660 */   828,  370, 1051,  379,  411, 1064, 1358,  207,  408,  773,
+ /*   670 */   829, 1079, 1080, 1081,   64,   64,  322,   64,   64, 1302,
+ /*   680 */   947,  411,  410, 1358, 1360,  112,  113,  103, 1100, 1100,
+ /*   690 */   953,  956,  946,  946,  110,  110,  111,  111,  111,  111,
+ /*   700 */   294,  482,  515, 1037, 1487,  515,  434, 1487,  354, 1120,
+ /*   710 */   483,  996,  913,  485,  466,  996,  132,  178,   33,  450,
+ /*   720 */  1203,  136,  406,   64,   64,  479,   64,   64,  419,  369,
+ /*   730 */   283, 1146,  252,  252,  109,  109,  109,  109,  108,  108,
+ /*   740 */   107,  107,  107,  106,  401,  512,  224,  440,  411,  266,
+ /*   750 */  1358,  266,  252,  252,  370,  296,  416,  284,  934,  396,
+ /*   760 */   976,  470,  400,  252,  252,  512,    9,  473,  231,  500,
+ /*   770 */   354, 1036, 1035, 1488,  355,  374,  512, 1121,  112,  113,
+ /*   780 */   103, 1100, 1100,  953,  956,  946,  946,  110,  110,  111,
+ /*   790 */   111,  111,  111,  252,  252, 1015,  515, 1347,  295,  252,
+ /*   800 */   252,  252,  252, 1098,  375,  249,  512,  445,  872,  322,
+ /*   810 */  1016,  480,  512,  195,  512,  434,  273,   15,   15,  515,
+ /*   820 */   314,  515,   95,  515,   93, 1017,  367,  109,  109,  109,
+ /*   830 */   109,  108,  108,  107,  107,  107,  106,  401,  515, 1121,
+ /*   840 */    39,   39,   51,   51,   52,   52,  503,  370,  515, 1204,
+ /*   850 */  1098,  918,  439,  341,  133,  436,  223,  222,  221,   53,
+ /*   860 */    53,  322, 1400,  761,  762,  763,  515,  370,   88,   54,
+ /*   870 */    54,  112,  113,  103, 1100, 1100,  953,  956,  946,  946,
+ /*   880 */   110,  110,  111,  111,  111,  111,  407,   55,   55,  196,
+ /*   890 */   515,  112,  113,  103, 1100, 1100,  953,  956,  946,  946,
+ /*   900 */   110,  110,  111,  111,  111,  111,  135,  264, 1149,  376,
+ /*   910 */   515,   40,   40,  515,  872,  515,  993,  515,  993,  116,
+ /*   920 */   109,  109,  109,  109,  108,  108,  107,  107,  107,  106,
+ /*   930 */   401,   41,   41,  515,   43,   43,   44,   44,   56,   56,
+ /*   940 */   109,  109,  109,  109,  108,  108,  107,  107,  107,  106,
+ /*   950 */   401,  515,  379,  515,   57,   57,  515,  799,  515,  379,
+ /*   960 */   515,  445,  200,  515,  323,  515, 1397,  515, 1459,  515,
+ /*   970 */  1287,  817,   58,   58,   14,   14,  515,   59,   59,  118,
+ /*   980 */   118,   60,   60,  515,   46,   46,   61,   61,   62,   62,
+ /*   990 */    47,   47,  515,  190,  189,   91,  515,  140,  140,  515,
+ /*  1000 */   394,  515,  277, 1200,  141,  141,  515, 1115,  515,  992,
+ /*  1010 */   515,  992,  515,   69,   69,  370,  278,   48,   48,  259,
+ /*  1020 */    65,   65,  119,  119,  246,  246,  260,   66,   66,  120,
+ /*  1030 */   120,  121,  121,  117,  117,  370,  515,  512,  383,  112,
+ /*  1040 */   113,  103, 1100, 1100,  953,  956,  946,  946,  110,  110,
+ /*  1050 */   111,  111,  111,  111,  515,  872,  515,  139,  139,  112,
+ /*  1060 */   113,  103, 1100, 1100,  953,  956,  946,  946,  110,  110,
+ /*  1070 */   111,  111,  111,  111, 1287,  138,  138,  125,  125,  515,
+ /*  1080 */    12,  515,  281, 1287,  515,  445,  131, 1287,  109,  109,
+ /*  1090 */   109,  109,  108,  108,  107,  107,  107,  106,  401,  515,
+ /*  1100 */   124,  124,  122,  122,  515,  123,  123,  515,  109,  109,
+ /*  1110 */   109,  109,  108,  108,  107,  107,  107,  106,  401,  515,
+ /*  1120 */    68,   68,  463,  783,  515,   70,   70,  302,   67,   67,
+ /*  1130 */  1032,  253,  253,  356, 1287,  191,  196, 1433,  465, 1301,
+ /*  1140 */    38,   38,  384,   94,  512,   42,   42,  177,  848,  274,
+ /*  1150 */   506,  385,  420,  847, 1356,  441,  508,  376,  377,  153,
+ /*  1160 */   423,  872,  432,  370,  224,  251,  194,  887,  182,  293,
+ /*  1170 */   783,  848,   88,  254,  466,  888,  847,  915,  807,  806,
+ /*  1180 */   230, 1241,  910,  370,   17,  413,  797,  112,  113,  103,
+ /*  1190 */  1100, 1100,  953,  956,  946,  946,  110,  110,  111,  111,
+ /*  1200 */   111,  111,  395,  814,  815, 1175,  983,  112,  101,  103,
+ /*  1210 */  1100, 1100,  953,  956,  946,  946,  110,  110,  111,  111,
+ /*  1220 */   111,  111,  375,  422,  427,  429,  298,  230,  230,   88,
+ /*  1230 */  1240,  451,  312,  797,  226,   88,  109,  109,  109,  109,
+ /*  1240 */   108,  108,  107,  107,  107,  106,  401,   86,  433,  979,
+ /*  1250 */   927,  881,  226,  983,  230,  415,  109,  109,  109,  109,
+ /*  1260 */   108,  108,  107,  107,  107,  106,  401,  320,  845,  781,
+ /*  1270 */   846,  100,  130,  100, 1403,  290,  370,  319, 1377, 1376,
+ /*  1280 */   437, 1449,  299, 1237,  303,  306,  308,  310, 1188, 1174,
+ /*  1290 */  1173, 1172,  315,  324,  325, 1228,  370,  927, 1249,  271,
+ /*  1300 */  1286,  113,  103, 1100, 1100,  953,  956,  946,  946,  110,
+ /*  1310 */   110,  111,  111,  111,  111, 1224, 1235,  502,  501, 1292,
+ /*  1320 */  1221, 1155,  103, 1100, 1100,  953,  956,  946,  946,  110,
+ /*  1330 */   110,  111,  111,  111,  111, 1148, 1137, 1136, 1138, 1443,
+ /*  1340 */   446,  244,  184,   98,  507,  188,    4,  353,  327,  109,
+ /*  1350 */   109,  109,  109,  108,  108,  107,  107,  107,  106,  401,
+ /*  1360 */   510,  329,  331,  199,  414,  456,  292,  285,  318,  109,
+ /*  1370 */   109,  109,  109,  108,  108,  107,  107,  107,  106,  401,
+ /*  1380 */    11, 1271, 1279,  402,  361,  192, 1171, 1351,  431,  505,
+ /*  1390 */   346, 1350,  333,   98,  507,  504,    4,  187, 1446, 1115,
+ /*  1400 */   233, 1396,  155, 1394, 1112,  152,   72,   75,  378,  425,
+ /*  1410 */   510,  165,  149,  157,  933, 1276,   86,   30, 1268,  417,
+ /*  1420 */    96,   96,    8,  160,  161,  162,  163,   97,  418,  402,
+ /*  1430 */   517,  516,  449,  402,  923,  210,  358,  424, 1282,  438,
+ /*  1440 */   169,  214,  360, 1345,   80,  504,   31,  444, 1365,  301,
+ /*  1450 */   245,  274,  506,  216,  174,  305,  488,  447,  217,  462,
+ /*  1460 */  1139,  487,  218,  363,  933,  923,  923,  925,  926,   24,
+ /*  1470 */    96,   96, 1191, 1190, 1189,  391, 1182,   97, 1163,  402,
+ /*  1480 */   517,  516,  799,  364,  923, 1162,  317, 1161,   98,  507,
+ /*  1490 */  1181,    4, 1458,  472,  393,  269,  270,  475,  481, 1232,
+ /*  1500 */    85, 1233,  326,  328,  232,  510,  495, 1231,  330,   98,
+ /*  1510 */   507, 1230,    4,  486,  335,  923,  923,  925,  926,   24,
+ /*  1520 */  1435, 1068,  404,  181,  336,  256,  510,  115,  402,  332,
+ /*  1530 */   352,  352,  351,  241,  349, 1214, 1414,  770,  338,   10,
+ /*  1540 */   504,  340,  272,   92, 1331, 1213,   87,  183,  484,  402,
+ /*  1550 */   201,  488,  280,  239,  344,  345,  489, 1145,   29,  933,
+ /*  1560 */   279,  504, 1074,  518,  240,   96,   96,  242,  243,  519,
+ /*  1570 */  1134, 1129,   97,  154,  402,  517,  516,  372,  373,  923,
+ /*  1580 */   933,  142,  143,  128, 1381,  267,   96,   96,  852,  757,
+ /*  1590 */   203,  144,  403,   97, 1382,  402,  517,  516,  204, 1380,
+ /*  1600 */   923,  146, 1379, 1159, 1158,   71, 1156,  276,  202,  185,
+ /*  1610 */   923,  923,  925,  926,   24,  198,  257,  126,  991,  989,
+ /*  1620 */   907,   98,  507,  156,    4,  145,  158,  206,  831,  209,
+ /*  1630 */   291,  923,  923,  925,  926,   24, 1005,  911,  510,  164,
+ /*  1640 */   147,  380,  371,  382,  166,   76,   77,  274,  506,  148,
+ /*  1650 */    78,   79, 1008,  211,  212, 1004,  137,  213,   18,  300,
+ /*  1660 */   230,  402,  997, 1109,  443,  215,   32,  170,  171,  772,
+ /*  1670 */   409,  448,  319,  504,  219,  172,  452,   81,   19,  457,
+ /*  1680 */   313,   20,   82,  268,  488,  150,  810,  179,   83,  487,
+ /*  1690 */   464,  151,  933,  180,  959,   84, 1040,   34,   96,   96,
+ /*  1700 */   471, 1041,   35,  474,  193,   97,  248,  402,  517,  516,
+ /*  1710 */  1068,  404,  923,  250,  256,  880,  229,  175,  875,  352,
+ /*  1720 */   352,  351,  241,  349,  100,   21,  770,   22, 1054, 1056,
+ /*  1730 */     7,   98,  507, 1045,    4,  337, 1058,   23,  974,  201,
+ /*  1740 */   176,  280,   88,  923,  923,  925,  926,   24,  510,  279,
+ /*  1750 */   960,  958,  962, 1014,  963, 1013,  235,  234,   25,   36,
+ /*  1760 */    99,   90,  507,  928,    4,  511,  350,  782,   26,  841,
+ /*  1770 */   236,  402,  347, 1069,  237, 1125, 1125, 1451,  510,  203,
+ /*  1780 */  1450, 1125, 1125,  504, 1125, 1125, 1125,  204, 1125, 1125,
+ /*  1790 */   146, 1125, 1125, 1125, 1125, 1125, 1125,  202, 1125, 1125,
+ /*  1800 */  1125,  402,  933, 1125, 1125, 1125, 1125, 1125,   96,   96,
+ /*  1810 */  1125, 1125, 1125,  504, 1125,   97, 1125,  402,  517,  516,
+ /*  1820 */  1125, 1125,  923, 1125, 1125, 1125, 1125, 1125, 1125, 1125,
+ /*  1830 */  1125,  371,  933, 1125, 1125, 1125,  274,  506,   96,   96,
+ /*  1840 */  1125, 1125, 1125, 1125, 1125,   97, 1125,  402,  517,  516,
+ /*  1850 */  1125, 1125,  923,  923,  923,  925,  926,   24, 1125,  409,
+ /*  1860 */  1125, 1125, 1125,  256, 1125, 1125, 1125, 1125,  352,  352,
+ /*  1870 */   351,  241,  349, 1125, 1125,  770, 1125, 1125, 1125, 1125,
+ /*  1880 */  1125, 1125, 1125,  923,  923,  925,  926,   24,  201, 1125,
+ /*  1890 */   280, 1125, 1125, 1125, 1125, 1125, 1125, 1125,  279, 1125,
+ /*  1900 */  1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125,
+ /*  1910 */  1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125,
+ /*  1920 */  1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125,  203, 1125,
+ /*  1930 */  1125, 1125, 1125, 1125, 1125, 1125,  204, 1125, 1125,  146,
+ /*  1940 */  1125, 1125, 1125, 1125, 1125, 1125,  202, 1125, 1125, 1125,
+ /*  1950 */  1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125,
+ /*  1960 */  1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125,
+ /*  1970 */  1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125,
+ /*  1980 */   371, 1125, 1125, 1125, 1125,  274,  506, 1125, 1125, 1125,
+ /*  1990 */  1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125,
+ /*  2000 */  1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125,  409,
 };
 static const YYCODETYPE yy_lookahead[] = {
- /*     0 */   174,  226,  227,  228,  226,  227,  228,  172,  145,  146,
- /*    10 */   147,  148,  149,  150,  153,  169,  170,  171,  155,   19,
- /*    20 */   157,  246,  192,  193,  177,  181,  182,  164,  169,  170,
- /*    30 */   171,   31,  164,  153,  190,  174,  175,  187,  153,   39,
- /*    40 */     7,    8,    9,   43,   44,   45,   46,   47,   48,   49,
- /*    50 */    50,   51,   52,   53,   54,   55,   56,   57,  174,  196,
- /*    60 */   197,  226,  227,  228,  196,  197,   46,   47,   48,   49,
- /*    70 */   209,  208,   19,  226,  227,  228,  208,  174,  177,   26,
- /*    80 */   195,  213,  214,   22,  221,   85,   86,   87,   88,   89,
- /*    90 */    90,   91,   92,   93,   94,   95,   43,   44,   45,   46,
- /*   100 */    47,   48,   49,   50,   51,   52,   53,   54,   55,   56,
- /*   110 */    57,  172,  249,  153,   53,  153,  147,  148,  149,  150,
- /*   120 */    22,   23,   69,  103,  155,   19,  157,  226,  227,  228,
- /*   130 */    94,   95,  247,  164,  174,  175,  174,  175,   85,   86,
- /*   140 */    87,   88,   89,   90,   91,   92,   93,   94,   95,   43,
- /*   150 */    44,   45,   46,   47,   48,   49,   50,   51,   52,   53,
- /*   160 */    54,   55,   56,   57,  153,  196,  197,  153,  153,  209,
- /*   170 */   210,  209,  210,   67,   95,  161,  237,  208,   19,  165,
- /*   180 */   165,  242,   84,   24,   91,   92,   93,   94,   95,  223,
- /*   190 */   221,   85,   86,   87,   88,   89,   90,   91,   92,   93,
- /*   200 */    94,   95,   43,   44,   45,   46,   47,   48,   49,   50,
- /*   210 */    51,   52,   53,   54,   55,   56,   57,  153,  249,   85,
- /*   220 */    86,   87,   88,   89,   90,   91,   92,   93,   94,   95,
- /*   230 */   219,   19,  109,  110,  111,   23,   89,   90,   91,   92,
- /*   240 */    93,   94,   95,   73,   85,   86,   87,   88,   89,   90,
- /*   250 */    91,   92,   93,   94,   95,   43,   44,   45,   46,   47,
- /*   260 */    48,   49,   50,   51,   52,   53,   54,   55,   56,   57,
- /*   270 */   153,   22,   23,  101,  173,   26,  104,  105,  106,  109,
- /*   280 */   110,  111,  181,   11,   19,   59,  114,   73,   23,  110,
- /*   290 */   111,  174,  175,  116,   80,  118,  119,   85,   86,   87,
- /*   300 */    88,   89,   90,   91,   92,   93,   94,   95,   43,   44,
- /*   310 */    45,   46,   47,   48,   49,   50,   51,   52,   53,   54,
- /*   320 */    55,   56,   57,  109,   98,   99,  100,  101,   83,  153,
- /*   330 */   104,  105,  106,   84,  120,  121,  153,   19,  192,  193,
- /*   340 */   114,   23,   89,   90,   99,   59,   23,  230,  103,   26,
- /*   350 */    85,   86,   87,   88,   89,   90,   91,   92,   93,   94,
- /*   360 */    95,   43,   44,   45,   46,   47,   48,   49,   50,   51,
- /*   370 */    52,   53,   54,   55,   56,   57,  153,   91,  153,  134,
- /*   380 */   135,  136,  110,  111,   98,   99,  100,  134,  153,  136,
- /*   390 */    19,   22,   23,   26,   23,   26,   80,  174,  175,  174,
- /*   400 */   175,   59,  219,   85,   86,   87,   88,   89,   90,   91,
- /*   410 */    92,   93,   94,   95,   43,   44,   45,   46,   47,   48,
- /*   420 */    49,   50,   51,   52,   53,   54,   55,   56,   57,   16,
- /*   430 */   153,   22,  209,  210,  209,  210,  120,  121,  196,  197,
- /*   440 */    98,   99,  100,   19,   46,   22,   23,   23,  252,  253,
- /*   450 */   208,  174,  175,   84,  219,  153,   85,   86,   87,   88,
- /*   460 */    89,   90,   91,   92,   93,   94,   95,   43,   44,   45,
- /*   470 */    46,   47,   48,   49,   50,   51,   52,   53,   54,   55,
- /*   480 */    56,   57,  153,  153,  153,  153,  209,  120,  121,   76,
- /*   490 */   153,   78,  109,  110,  111,   97,   19,  153,   89,   90,
- /*   500 */   198,   59,  183,  174,  175,  174,  175,   84,  153,   85,
- /*   510 */    86,   87,   88,   89,   90,   91,   92,   93,   94,   95,
- /*   520 */    43,   44,   45,   46,   47,   48,   49,   50,   51,   52,
- /*   530 */    53,   54,   55,   56,   57,   16,  197,  153,   22,  153,
- /*   540 */   153,   99,  198,   12,  153,  196,  197,  208,  153,  153,
- /*   550 */   195,  183,   19,   23,  222,  142,   26,  208,   27,  153,
- /*   560 */   174,  175,   85,   86,   87,   88,   89,   90,   91,   92,
- /*   570 */    93,   94,   95,   42,  188,   59,   43,   44,   45,   46,
- /*   580 */    47,   48,   49,   50,   51,   52,   53,   54,   55,   56,
- /*   590 */    57,  195,   22,  198,   63,   76,  153,   78,  167,  168,
- /*   600 */   153,  195,  167,  168,   73,  153,  222,  153,   19,  222,
- /*   610 */   153,  220,  153,   24,   98,   99,  100,  140,   85,   86,
- /*   620 */    87,   88,   89,   90,   91,   92,   93,   94,   95,   59,
- /*   630 */   100,  153,   43,   44,   45,   46,   47,   48,   49,   50,
- /*   640 */    51,   52,   53,   54,   55,   56,   57,  195,  153,  195,
- /*   650 */   153,  153,  174,  175,   26,  125,  120,  121,  153,  213,
- /*   660 */   214,   19,  153,  220,  153,  153,  188,  220,   98,   99,
- /*   670 */   100,  174,  175,  140,   85,   86,   87,   88,   89,   90,
- /*   680 */    91,   92,   93,   94,   95,   43,   44,   45,   46,   47,
+ /*     0 */   184,  238,  239,  240,  238,  239,  240,  163,  155,  156,
+ /*    10 */   157,  158,  159,  160,  163,  191,  192,  183,  165,   19,
+ /*    20 */   167,  258,  202,  203,  200,  191,  163,  174,  184,  185,
+ /*    30 */   174,   31,  163,  163,  171,  184,  185,   35,  175,   39,
+ /*    40 */   179,  180,  181,   43,   44,   45,   46,   47,   48,   49,
+ /*    50 */    50,   51,   52,   53,   54,   55,   56,   57,  184,  206,
+ /*    60 */   207,  163,  206,  207,  220,  163,   16,  163,   66,  163,
+ /*    70 */    59,  270,  219,  229,  273,  219,   74,  208,  174,  223,
+ /*    80 */   224,  163,  184,  185,  163,  232,  184,  185,  184,  185,
+ /*    90 */   184,  185,   92,   93,   94,   95,   96,   97,   98,   99,
+ /*   100 */   100,  101,  102,  233,  198,  184,  185,   96,   97,  163,
+ /*   110 */   206,  207,   19,  163,  261,  104,  105,  106,  107,  198,
+ /*   120 */   109,  119,  220,  219,  220,  274,  275,   77,  117,   79,
+ /*   130 */   187,  229,   19,  229,  184,  185,   43,   44,   45,   46,
+ /*   140 */    47,   48,   49,   50,   51,   52,   53,   54,   55,   56,
+ /*   150 */    57,  233,  141,  134,  143,  102,   43,   44,   45,   46,
+ /*   160 */    47,   48,   49,   50,   51,   52,   53,   54,   55,   56,
+ /*   170 */    57,  152,  274,  216,  276,  218,   83,  163,   85,  233,
+ /*   180 */    67,  238,  239,  240,   11,   92,   93,   94,   95,   96,
+ /*   190 */    97,   98,   99,  100,  101,  102,   19,   54,   55,   56,
+ /*   200 */    57,   58,  163,   26,  163,   92,   93,   94,   95,   96,
+ /*   210 */    97,   98,   99,  100,  101,  102,   54,   55,   56,   57,
+ /*   220 */    43,   44,   45,   46,   47,   48,   49,   50,   51,   52,
+ /*   230 */    53,   54,   55,   56,   57,   92,   93,   94,   95,   96,
+ /*   240 */    97,   98,   99,  100,  101,  102,   69,   96,   97,   98,
+ /*   250 */    99,  100,  101,  102,   92,   93,   94,   95,   96,   97,
+ /*   260 */    98,   99,  100,  101,  102,   81,  179,  180,  181,   92,
+ /*   270 */    93,   94,   95,   96,   97,   98,   99,  100,  101,  102,
+ /*   280 */   163,  267,  268,  163,   22,   23,   59,  163,   26,   19,
+ /*   290 */   117,  118,  175,  109,   24,   59,   92,   93,   94,   95,
+ /*   300 */    96,   97,   98,   99,  100,  101,  102,  268,  184,  185,
+ /*   310 */   269,  127,  128,   43,   44,   45,   46,   47,   48,   49,
+ /*   320 */    50,   51,   52,   53,   54,   55,   56,   57,  157,  158,
+ /*   330 */   159,  160,  105,  106,  107,  163,  165,   59,  167,  184,
+ /*   340 */    90,  105,  106,  107,  108,  174,   73,  111,  112,  113,
+ /*   350 */    19,   22,  163,   91,   81,  163,  106,  121,   81,  132,
+ /*   360 */   110,   16,   92,   93,   94,   95,   96,   97,   98,   99,
+ /*   370 */   100,  101,  102,  184,  185,  255,   98,  206,  207,   26,
+ /*   380 */   101,  102,   19,  105,  106,  107,   23,  198,   59,  116,
+ /*   390 */   219,  141,  142,  143,   24,  163,  187,  205,  274,  275,
+ /*   400 */   127,  128,  182,  232,  127,  128,   43,   44,   45,   46,
+ /*   410 */    47,   48,   49,   50,   51,   52,   53,   54,   55,   56,
+ /*   420 */    57,  158,   77,  160,   79,   59,   26,  182,  165,   59,
+ /*   430 */   167,  199,  261,  102,  105,  106,  107,  174,   72,  108,
+ /*   440 */   109,  110,  111,  112,  113,  114,   59,  238,  239,  240,
+ /*   450 */   123,  120,  125,  126,  163,   92,   93,   94,   95,   96,
+ /*   460 */    97,   98,   99,  100,  101,  102,  163,  163,  163,  206,
+ /*   470 */   207,  105,  106,  107,  254,   19,  106,   90,  197,   23,
+ /*   480 */   127,  128,  219,  238,  239,  240,   22,  184,  185,  184,
+ /*   490 */   185,   22,  105,  106,  149,  232,  205,  110,  163,   43,
+ /*   500 */    44,   45,   46,   47,   48,   49,   50,   51,   52,   53,
+ /*   510 */    54,   55,   56,   57,   98,   99,  100,  101,  102,  184,
+ /*   520 */   185,  163,   53,   59,  261,  220,  117,  118,  141,  142,
+ /*   530 */   143,  131,  174,   59,  229,  116,  117,  118,  163,   59,
+ /*   540 */   163,  163,  184,  185,   59,  242,   72,   22,   92,   93,
+ /*   550 */    94,   95,   96,   97,   98,   99,  100,  101,  102,  184,
+ /*   560 */   185,   24,  184,  185,  206,  207,  202,  203,   19,  105,
+ /*   570 */   106,  107,   23,  198,   22,  174,  198,  219,  220,  105,
+ /*   580 */   106,  107,   96,   97,   59,  105,  106,  107,   22,  174,
+ /*   590 */    59,  106,   43,   44,   45,   46,   47,   48,   49,   50,
+ /*   600 */    51,   52,   53,   54,   55,   56,   57,  206,  207,   12,
+ /*   610 */   108,   59,  132,  111,  112,  113,   46,   47,   48,   49,
+ /*   620 */   219,  206,  207,  121,   27,   59,  163,  141,  207,  143,
+ /*   630 */   105,  106,  107,  163,  219,  234,  105,  106,  107,   42,
+ /*   640 */   219,   92,   93,   94,   95,   96,   97,   98,   99,  100,
+ /*   650 */   101,  102,   76,  163,  184,  185,  163,  105,  106,  107,
+ /*   660 */    63,   19,   86,  163,  163,   23,  163,  130,  205,   21,
+ /*   670 */    73,  105,  106,  107,  184,  185,  163,  184,  185,  237,
+ /*   680 */   110,  180,  181,  180,  181,   43,   44,   45,   46,   47,
  /*   690 */    48,   49,   50,   51,   52,   53,   54,   55,   56,   57,
- /*   700 */   243,  189,  243,  198,  172,  250,  251,  117,   31,  201,
- /*   710 */    26,  139,  122,  141,   19,  220,   39,   29,  220,  211,
- /*   720 */    24,   33,  153,  164,  153,  164,   19,   85,   86,   87,
- /*   730 */    88,   89,   90,   91,   92,   93,   94,   95,   43,   44,
- /*   740 */    45,   46,   47,   48,   49,   50,   51,   52,   53,   54,
- /*   750 */    55,   56,   57,   65,  243,  196,  197,  196,  197,  131,
- /*   760 */   189,   22,  103,   24,  153,   23,   19,  208,   26,  208,
- /*   770 */   102,  103,  113,   23,  242,   22,   26,  134,  164,  136,
- /*   780 */    85,   86,   87,   88,   89,   90,   91,   92,   93,   94,
- /*   790 */    95,   44,   45,   46,   47,   48,   49,   50,   51,   52,
- /*   800 */    53,   54,   55,   56,   57,   98,  153,  153,  124,  153,
- /*   810 */   196,  197,   23,   23,   61,   26,   26,   19,   23,  123,
- /*   820 */    23,   26,  208,   26,    7,    8,  153,   22,  174,  175,
- /*   830 */   174,  175,   85,   86,   87,   88,   89,   90,   91,   92,
- /*   840 */    93,   94,   95,   45,   46,   47,   48,   49,   50,   51,
- /*   850 */    52,   53,   54,   55,   56,   57,   19,   20,   59,   22,
- /*   860 */   111,   59,  164,   23,   59,   23,   26,  153,   26,   59,
- /*   870 */   153,   72,   23,   36,   72,   26,   35,   23,   59,  134,
- /*   880 */    26,  136,  133,   85,   86,   87,   88,   89,   90,   91,
- /*   890 */    92,   93,   94,   95,  196,  197,   59,   98,   99,  100,
- /*   900 */    98,   99,  100,   98,   99,  100,  208,   66,   71,   99,
- /*   910 */    54,   55,   56,   57,   58,   74,  153,   80,   99,   19,
- /*   920 */    83,  223,   23,   26,  153,   26,   89,   90,   54,   55,
- /*   930 */    56,   57,  153,   96,  153,   98,   99,  100,   22,  153,
- /*   940 */   103,   85,   86,   87,   88,   89,   90,   91,   92,   93,
- /*   950 */    94,   95,  183,  112,  158,  174,  175,  120,  121,   85,
- /*   960 */    86,   87,   88,   89,   90,   91,   92,   93,   94,   95,
- /*   970 */   215,  134,  135,  136,  137,  138,    0,    1,    2,   23,
- /*   980 */    21,    5,   26,  153,   22,   59,   10,   11,   12,   13,
- /*   990 */    14,    1,    2,   17,  212,    5,  153,  153,   98,  153,
- /*  1000 */    10,   11,   12,   13,   14,  108,   30,   17,   32,  193,
- /*  1010 */   153,   59,  153,  153,  170,  171,   40,  174,  175,  153,
- /*  1020 */    30,   59,   32,   19,   20,   99,   22,  170,  171,  233,
- /*  1030 */    40,  188,  236,  174,  175,  153,  153,  153,   79,  123,
- /*  1040 */    36,   89,   90,  153,  153,  153,   70,  188,  153,   97,
- /*  1050 */    98,   99,  100,   77,  102,  153,   80,   81,  174,  175,
- /*  1060 */    70,   99,  110,   59,  105,  174,  175,   77,  153,  238,
- /*  1070 */    80,   81,  188,   19,   20,   71,   22,  153,  153,  235,
- /*  1080 */    19,   22,  164,   24,   59,  153,  134,   83,  136,  153,
- /*  1090 */    36,  115,  235,   89,   90,   91,  120,  121,  153,  153,
- /*  1100 */    96,  142,   98,   99,  100,  115,   59,  103,   83,  239,
- /*  1110 */   120,  121,  199,   59,  196,  197,  153,  153,   59,  143,
- /*  1120 */   174,  175,  153,   98,   99,   71,  208,  153,  103,  165,
- /*  1130 */   153,   19,   20,  143,   22,  153,  153,   83,  134,  135,
- /*  1140 */   136,  137,  138,   89,   90,   98,   99,  100,   36,  185,
- /*  1150 */    96,  187,   98,   99,  100,   91,   95,  103,   99,  134,
- /*  1160 */   135,  136,  101,  102,  103,  104,  105,  106,  107,  153,
- /*  1170 */    26,   59,  125,  164,  113,  153,  153,  153,  212,   12,
- /*  1180 */    19,  117,  153,   71,  153,  212,  122,  164,  134,  135,
- /*  1190 */   136,  137,  138,  212,   27,   83,  212,  174,  175,   59,
- /*  1200 */   200,   89,   90,  174,  175,  196,  197,   46,   96,   42,
- /*  1210 */    98,   99,  100,  172,  151,  103,    5,  208,  203,  196,
- /*  1220 */   197,   10,   11,   12,   13,   14,  216,  216,   17,  244,
- /*  1230 */    63,  208,  209,  210,  153,   80,   24,  203,   98,   99,
- /*  1240 */   100,   30,   22,   32,  100,  164,  134,  135,  136,  137,
- /*  1250 */   138,   40,  148,  164,  150,  174,  175,  102,   97,  155,
- /*  1260 */   203,  157,  164,  244,  178,  125,  186,  182,  164,  125,
- /*  1270 */   177,   59,  177,  177,  113,  120,  121,  196,  197,   59,
- /*  1280 */   232,   70,  153,  216,  202,  196,  197,  153,   77,  208,
- /*  1290 */   209,   80,   81,  156,  196,  197,   60,  208,  248,  200,
- /*  1300 */   196,  197,  153,  174,  175,  123,  208,  153,  174,  175,
- /*  1310 */   160,   99,  208,  153,   38,  153,  160,  153,   98,   99,
- /*  1320 */   100,  153,  245,  174,  175,  221,  115,  153,  174,  175,
- /*  1330 */   153,  120,  121,  245,  174,  175,  174,  175,  174,  175,
- /*  1340 */   160,  153,  174,  175,  153,  225,  153,   22,  174,  175,
- /*  1350 */    97,  174,  175,  249,  143,  153,  224,  153,   43,  153,
- /*  1360 */   191,  153,  174,  175,   18,  174,  175,  174,  175,  153,
- /*  1370 */   131,  153,  194,  203,  153,  194,  174,  175,  174,  175,
- /*  1380 */   174,  175,  174,  175,  153,  160,  153,   18,  153,  194,
- /*  1390 */   174,  175,  174,  175,  153,  174,  175,  153,  225,  153,
- /*  1400 */   203,  153,  159,  153,  194,  174,  175,  174,  175,  174,
- /*  1410 */   175,  153,  203,  153,  224,  174,  175,  191,  174,  175,
- /*  1420 */   174,  175,  174,  175,  174,  175,  203,  160,  153,  191,
- /*  1430 */   153,  159,  174,  175,  174,  175,  153,  139,   62,  153,
- /*  1440 */   241,  153,  160,  153,  159,  153,   22,  240,  179,  174,
- /*  1450 */   175,  174,  175,  160,  159,   97,  160,  174,  175,  159,
- /*  1460 */   174,  175,  174,  175,  174,  175,  174,  175,  179,   64,
- /*  1470 */   176,  184,  108,  176,   95,  176,  234,  126,  176,  234,
- /*  1480 */   179,  178,  176,  176,  176,   97,  218,  217,  184,  179,
- /*  1490 */   179,  218,  218,  160,   22,  217,  217,  160,  218,  139,
- /*  1500 */   229,  217,  130,  129,  127,   25,  128,  163,   26,  162,
- /*  1510 */    13,  206,  231,  154,    6,  154,  207,  205,  204,  203,
- /*  1520 */   152,  166,  152,  152,  172,  172,  172,    4,  172,  166,
- /*  1530 */   180,  166,    3,   22,  172,  144,   15,  180,  172,  172,
- /*  1540 */    82,   16,   23,   23,  121,  254,  132,  172,  112,  124,
- /*  1550 */    24,   20,  126,   16,    1,  124,  112,   61,   53,   37,
- /*  1560 */   133,  132,   53,   53,  112,   53,   98,  254,  251,   34,
- /*  1570 */   123,    1,    5,   22,   97,  142,   26,   75,  123,   41,
- /*  1580 */    97,   68,   68,   24,   20,   19,  113,   22,  107,   28,
- /*  1590 */    22,   67,   23,   22,   22,   67,   22,   67,   23,   37,
- /*  1600 */    23,   23,   26,   23,   22,   24,   23,   22,   24,  123,
- /*  1610 */    23,   23,   22,   98,  125,   26,   11,   23,   26,   23,
- /*  1620 */    34,   23,   23,   23,   23,   34,   22,   34,   26,   22,
- /*  1630 */    22,   15,   23,   23,   22,  117,   23,   22,    1,  123,
- /*  1640 */    26,   23,  255,  255,  255,  255,  255,  255,  255,  255,
- /*  1650 */   123,  255,  255,  255,  255,  123,  123,  255,  255,  255,
- /*  1660 */   255,  255,  255,  255,  255,  255,  255,  255,  255,  255,
- /*  1670 */   255,  255,  255,  255,  255,  255,  255,  255,  255,  255,
- /*  1680 */   255,  255,  255,  255,  255,  255,  255,  255,  255,  255,
- /*  1690 */   255,  255,  255,  255,  255,  255,  255,  255,  255,  255,
- /*  1700 */   255,  255,  255,  255,  255,  255,  255,  255,  255,  255,
- /*  1710 */   255,  255,  255,  255,  255,  255,  255,  255,  255,  255,
- /*  1720 */   255,  255,  255,  255,  255,  255,  255,  255,  255,  255,
- /*  1730 */   255,  255,  255,  255,  255,  255,  255,  255,  255,  255,
- /*  1740 */   255,  255,  255,  255,  255,  255,  255,  255,  255,  255,
- /*  1750 */   255,  255,  255,  255,  255,  255,  255,  255,  255,  255,
- /*  1760 */   255,  255,  255,  255,  255,  255,  255,  255,  255,  255,
- /*  1770 */   255,  255,  255,  255,  255,  255,  255,  255,  255,  255,
- /*  1780 */   255,  255,  255,  255,  255,  255,  255,  255,  255,  255,
- /*  1790 */   255,  255,  255,  255,  255,  255,  255,  255,  255,  255,
- /*  1800 */   255,  255,
+ /*   700 */   174,  163,  163,   22,   23,  163,  163,   26,   22,   23,
+ /*   710 */   220,   29,   73,  220,  272,   33,   22,  163,   24,   19,
+ /*   720 */   174,  208,  259,  184,  185,   19,  184,  185,   80,  175,
+ /*   730 */   230,  174,  206,  207,   92,   93,   94,   95,   96,   97,
+ /*   740 */    98,   99,  100,  101,  102,  219,   46,   65,  247,  195,
+ /*   750 */   247,  197,  206,  207,   19,  116,  117,  118,   23,  220,
+ /*   760 */   112,  174,  220,  206,  207,  219,   22,  174,   24,  174,
+ /*   770 */    22,   23,   91,  264,  265,  168,  219,   91,   43,   44,
+ /*   780 */    45,   46,   47,   48,   49,   50,   51,   52,   53,   54,
+ /*   790 */    55,   56,   57,  206,  207,   12,  163,  149,  255,  206,
+ /*   800 */   207,  206,  207,   59,  104,   23,  219,  163,   26,  163,
+ /*   810 */    27,  105,  219,  163,  219,  163,  211,  184,  185,  163,
+ /*   820 */   120,  163,  146,  163,  148,   42,  221,   92,   93,   94,
+ /*   830 */    95,   96,   97,   98,   99,  100,  101,  102,  163,   91,
+ /*   840 */   184,  185,  184,  185,  184,  185,   63,   19,  163,  205,
+ /*   850 */   106,   23,  245,  163,  208,  248,  116,  117,  118,  184,
+ /*   860 */   185,  163,  163,    7,    8,    9,  163,   19,   26,  184,
+ /*   870 */   185,   43,   44,   45,   46,   47,   48,   49,   50,   51,
+ /*   880 */    52,   53,   54,   55,   56,   57,  163,  184,  185,  107,
+ /*   890 */   163,   43,   44,   45,   46,   47,   48,   49,   50,   51,
+ /*   900 */    52,   53,   54,   55,   56,   57,  208,  255,  177,  178,
+ /*   910 */   163,  184,  185,  163,  132,  163,  141,  163,  143,   22,
+ /*   920 */    92,   93,   94,   95,   96,   97,   98,   99,  100,  101,
+ /*   930 */   102,  184,  185,  163,  184,  185,  184,  185,  184,  185,
+ /*   940 */    92,   93,   94,   95,   96,   97,   98,   99,  100,  101,
+ /*   950 */   102,  163,  163,  163,  184,  185,  163,  115,  163,  163,
+ /*   960 */   163,  163,   15,  163,  163,  163,  163,  163,   23,  163,
+ /*   970 */   163,   26,  184,  185,  184,  185,  163,  184,  185,  184,
+ /*   980 */   185,  184,  185,  163,  184,  185,  184,  185,  184,  185,
+ /*   990 */   184,  185,  163,   96,   97,  147,  163,  184,  185,  163,
+ /*  1000 */   199,  163,  163,  205,  184,  185,  163,   60,  163,  141,
+ /*  1010 */   163,  143,  163,  184,  185,   19,  163,  184,  185,  230,
+ /*  1020 */   184,  185,  184,  185,  206,  207,  230,  184,  185,  184,
+ /*  1030 */   185,  184,  185,  184,  185,   19,  163,  219,  231,   43,
+ /*  1040 */    44,   45,   46,   47,   48,   49,   50,   51,   52,   53,
+ /*  1050 */    54,   55,   56,   57,  163,   26,  163,  184,  185,   43,
+ /*  1060 */    44,   45,   46,   47,   48,   49,   50,   51,   52,   53,
+ /*  1070 */    54,   55,   56,   57,  163,  184,  185,  184,  185,  163,
+ /*  1080 */   182,  163,  163,  163,  163,  163,   22,  163,   92,   93,
+ /*  1090 */    94,   95,   96,   97,   98,   99,  100,  101,  102,  163,
+ /*  1100 */   184,  185,  184,  185,  163,  184,  185,  163,   92,   93,
+ /*  1110 */    94,   95,   96,   97,   98,   99,  100,  101,  102,  163,
+ /*  1120 */   184,  185,   98,   59,  163,  184,  185,  205,  184,  185,
+ /*  1130 */    23,  206,  207,   26,  163,   26,  107,  153,  154,  237,
+ /*  1140 */   184,  185,  231,  147,  219,  184,  185,  249,  124,  127,
+ /*  1150 */   128,  231,  254,  129,  163,  231,  177,  178,  262,  263,
+ /*  1160 */   118,  132,   19,   19,   46,  223,  224,   31,   24,   23,
+ /*  1170 */   106,  124,   26,   22,  272,   39,  129,   23,  109,  110,
+ /*  1180 */    26,  163,  140,   19,   22,  234,   59,   43,   44,   45,
+ /*  1190 */    46,   47,   48,   49,   50,   51,   52,   53,   54,   55,
+ /*  1200 */    56,   57,  231,    7,    8,  193,   59,   43,   44,   45,
+ /*  1210 */    46,   47,   48,   49,   50,   51,   52,   53,   54,   55,
+ /*  1220 */    56,   57,  104,   61,   23,   23,   23,   26,   26,   26,
+ /*  1230 */   163,   23,   23,  106,   26,   26,   92,   93,   94,   95,
+ /*  1240 */    96,   97,   98,   99,  100,  101,  102,  138,  105,   23,
+ /*  1250 */    59,   23,   26,  106,   26,  163,   92,   93,   94,   95,
+ /*  1260 */    96,   97,   98,   99,  100,  101,  102,  110,   23,   23,
+ /*  1270 */    23,   26,   26,   26,  163,  163,   19,  120,  163,  163,
+ /*  1280 */   163,  130,  163,  163,  163,  163,  163,  163,  163,  193,
+ /*  1290 */   193,  163,  163,  163,  163,  225,   19,  106,  163,  222,
+ /*  1300 */   163,   44,   45,   46,   47,   48,   49,   50,   51,   52,
+ /*  1310 */    53,   54,   55,   56,   57,  163,  163,  203,  163,  163,
+ /*  1320 */   222,  163,   45,   46,   47,   48,   49,   50,   51,   52,
+ /*  1330 */    53,   54,   55,   56,   57,  163,  163,  163,  163,  163,
+ /*  1340 */   251,  250,  209,   19,   20,  182,   22,  161,  222,   92,
+ /*  1350 */    93,   94,   95,   96,   97,   98,   99,  100,  101,  102,
+ /*  1360 */    36,  222,  222,  260,  226,  188,  256,  226,  187,   92,
+ /*  1370 */    93,   94,   95,   96,   97,   98,   99,  100,  101,  102,
+ /*  1380 */   210,  213,  213,   59,  213,  196,  192,  187,  256,  244,
+ /*  1390 */   212,  187,  226,   19,   20,   71,   22,  210,  166,   60,
+ /*  1400 */   130,  170,  260,  170,   38,   81,  257,  257,  170,  104,
+ /*  1410 */    36,   22,   43,  201,   90,  236,  138,  235,  213,   18,
+ /*  1420 */    96,   97,   48,  204,  204,  204,  204,  103,  170,  105,
+ /*  1430 */   106,  107,   18,   59,  110,  169,  213,  213,  201,  170,
+ /*  1440 */   201,  169,  236,  213,  146,   71,  235,   62,  253,  252,
+ /*  1450 */   170,  127,  128,  169,   22,  170,   82,  189,  169,  104,
+ /*  1460 */   170,   87,  169,  189,   90,  141,  142,  143,  144,  145,
+ /*  1470 */    96,   97,  186,  186,  186,   64,  194,  103,  186,  105,
+ /*  1480 */   106,  107,  115,  189,  110,  188,  186,  186,   19,   20,
+ /*  1490 */   194,   22,  186,  189,  102,  246,  246,  189,  133,  228,
+ /*  1500 */   104,  228,  227,  227,  170,   36,  134,  228,  227,   19,
+ /*  1510 */    20,  228,   22,   84,  271,  141,  142,  143,  144,  145,
+ /*  1520 */     0,    1,    2,  216,   22,    5,   36,  137,   59,  227,
+ /*  1530 */    10,   11,   12,   13,   14,  217,  269,   17,  216,   22,
+ /*  1540 */    71,  170,  243,  146,  241,  217,  136,  215,  135,   59,
+ /*  1550 */    30,   82,   32,   25,  214,  213,   87,  173,   26,   90,
+ /*  1560 */    40,   71,   13,  172,  164,   96,   97,  164,    6,  162,
+ /*  1570 */   162,  162,  103,  263,  105,  106,  107,  266,  266,  110,
+ /*  1580 */    90,  176,  176,  190,  182,  190,   96,   97,   98,    4,
+ /*  1590 */    70,  176,    3,  103,  182,  105,  106,  107,   78,  182,
+ /*  1600 */   110,   81,  182,  182,  182,  182,  182,  151,   88,   22,
+ /*  1610 */   141,  142,  143,  144,  145,   15,   89,   16,   23,   23,
+ /*  1620 */   128,   19,   20,  139,   22,  119,  131,   24,   20,  133,
+ /*  1630 */    16,  141,  142,  143,  144,  145,    1,  140,   36,  131,
+ /*  1640 */   119,   61,  122,   37,  139,   53,   53,  127,  128,  119,
+ /*  1650 */    53,   53,  105,   34,  130,    1,    5,  104,   22,  149,
+ /*  1660 */    26,   59,   68,   75,   41,  130,   24,   68,  104,   20,
+ /*  1670 */   150,   19,  120,   71,  114,   22,   67,   22,   22,   67,
+ /*  1680 */    23,   22,   22,   67,   82,   37,   28,   23,  138,   87,
+ /*  1690 */    22,  153,   90,   23,   23,   26,   23,   22,   96,   97,
+ /*  1700 */    24,   23,   22,   24,  130,  103,   23,  105,  106,  107,
+ /*  1710 */     1,    2,  110,   23,    5,  105,   34,   22,  132,   10,
+ /*  1720 */    11,   12,   13,   14,   26,   34,   17,   34,   85,   83,
+ /*  1730 */    44,   19,   20,   23,   22,   24,   75,   34,   23,   30,
+ /*  1740 */    26,   32,   26,  141,  142,  143,  144,  145,   36,   40,
+ /*  1750 */    23,   23,   23,   23,   11,   23,   22,   26,   22,   22,
+ /*  1760 */    22,   19,   20,   23,   22,   26,   15,   23,   22,  124,
+ /*  1770 */   130,   59,   23,    1,  130,  277,  277,  130,   36,   70,
+ /*  1780 */   130,  277,  277,   71,  277,  277,  277,   78,  277,  277,
+ /*  1790 */    81,  277,  277,  277,  277,  277,  277,   88,  277,  277,
+ /*  1800 */   277,   59,   90,  277,  277,  277,  277,  277,   96,   97,
+ /*  1810 */   277,  277,  277,   71,  277,  103,  277,  105,  106,  107,
+ /*  1820 */   277,  277,  110,  277,  277,  277,  277,  277,  277,  277,
+ /*  1830 */   277,  122,   90,  277,  277,  277,  127,  128,   96,   97,
+ /*  1840 */   277,  277,  277,  277,  277,  103,  277,  105,  106,  107,
+ /*  1850 */   277,  277,  110,  141,  142,  143,  144,  145,  277,  150,
+ /*  1860 */   277,  277,  277,    5,  277,  277,  277,  277,   10,   11,
+ /*  1870 */    12,   13,   14,  277,  277,   17,  277,  277,  277,  277,
+ /*  1880 */   277,  277,  277,  141,  142,  143,  144,  145,   30,  277,
+ /*  1890 */    32,  277,  277,  277,  277,  277,  277,  277,   40,  277,
+ /*  1900 */   277,  277,  277,  277,  277,  277,  277,  277,  277,  277,
+ /*  1910 */   277,  277,  277,  277,  277,  277,  277,  277,  277,  277,
+ /*  1920 */   277,  277,  277,  277,  277,  277,  277,  277,   70,  277,
+ /*  1930 */   277,  277,  277,  277,  277,  277,   78,  277,  277,   81,
+ /*  1940 */   277,  277,  277,  277,  277,  277,   88,  277,  277,  277,
+ /*  1950 */   277,  277,  277,  277,  277,  277,  277,  277,  277,  277,
+ /*  1960 */   277,  277,  277,  277,  277,  277,  277,  277,  277,  277,
+ /*  1970 */   277,  277,  277,  277,  277,  277,  277,  277,  277,  277,
+ /*  1980 */   122,  277,  277,  277,  277,  127,  128,  277,  277,  277,
+ /*  1990 */   277,  277,  277,  277,  277,  277,  277,  277,  277,  277,
+ /*  2000 */   277,  277,  277,  277,  277,  277,  277,  277,  150,  277,
+ /*  2010 */   277,  277,  277,  277,  277,  277,  277,  277,  277,
 };
-#define YY_SHIFT_COUNT    (489)
+#define YY_SHIFT_COUNT    (520)
 #define YY_SHIFT_MIN      (0)
-#define YY_SHIFT_MAX      (1637)
+#define YY_SHIFT_MAX      (1858)
 static const unsigned short int yy_shift_ofst[] = {
- /*     0 */   990,  976, 1211,  837,  837,  316, 1054, 1054, 1054, 1054,
- /*    10 */   214,    0,    0,  106,  642, 1054, 1054, 1054, 1054, 1054,
- /*    20 */  1054, 1054, 1054,  952,  952,  226, 1155,  316,  316,  316,
- /*    30 */   316,  316,  316,   53,  159,  212,  265,  318,  371,  424,
- /*    40 */   477,  533,  589,  642,  642,  642,  642,  642,  642,  642,
- /*    50 */   642,  642,  642,  642,  642,  642,  642,  642,  642,  642,
- /*    60 */   695,  642,  747,  798,  798, 1004, 1054, 1054, 1054, 1054,
- /*    70 */  1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054,
- /*    80 */  1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054,
- /*    90 */  1054, 1054, 1054, 1054, 1054, 1054, 1054, 1112, 1054, 1054,
- /*   100 */  1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054,
- /*   110 */  1054,  856,  874,  874,  874,  874,  874,  134,  147,   93,
- /*   120 */   342,  959, 1161,  253,  253,  342,  367,  367,  367,  367,
- /*   130 */   179,   36,   79, 1657, 1657, 1657, 1061, 1061, 1061,  516,
- /*   140 */   799,  516,  516,  531,  531,  802,  249,  369,  342,  342,
- /*   150 */   342,  342,  342,  342,  342,  342,  342,  342,  342,  342,
- /*   160 */   342,  342,  342,  342,  342,  342,  342,  342,  342,  272,
- /*   170 */   442,  442,  536, 1657, 1657, 1657, 1025,  245,  245,  570,
- /*   180 */   172,  286,  805, 1047, 1140, 1220,  342,  342,  342,  342,
- /*   190 */   342,  342,  342,  342,  170,  342,  342,  342,  342,  342,
- /*   200 */   342,  342,  342,  342,  342,  342,  342,  841,  841,  841,
- /*   210 */   342,  342,  342,  342,  530,  342,  342,  342, 1059,  342,
- /*   220 */   342, 1167,  342,  342,  342,  342,  342,  342,  342,  342,
- /*   230 */   123,  688,  177, 1212, 1212, 1212, 1212, 1144,  177,  177,
- /*   240 */  1064,  409,   33,  628,  707,  707,  900,  628,  628,  900,
- /*   250 */   897,  323,  398,  677,  677,  677,  707,  572,  684,  590,
- /*   260 */   739, 1236, 1182, 1182, 1276, 1276, 1182, 1253, 1325, 1315,
- /*   270 */  1239, 1346, 1346, 1346, 1346, 1182, 1369, 1239, 1239, 1253,
- /*   280 */  1325, 1315, 1315, 1239, 1182, 1369, 1298, 1376, 1182, 1369,
- /*   290 */  1424, 1182, 1369, 1182, 1369, 1424, 1358, 1358, 1358, 1405,
- /*   300 */  1424, 1358, 1364, 1358, 1405, 1358, 1358, 1424, 1379, 1379,
- /*   310 */  1424, 1351, 1388, 1351, 1388, 1351, 1388, 1351, 1388, 1182,
- /*   320 */  1472, 1182, 1360, 1372, 1377, 1374, 1378, 1239, 1480, 1482,
- /*   330 */  1497, 1497, 1508, 1508, 1508, 1657, 1657, 1657, 1657, 1657,
- /*   340 */  1657, 1657, 1657, 1657, 1657, 1657, 1657, 1657, 1657, 1657,
- /*   350 */  1657,   20,  413,   98,  423,  519,  383,  962,  742,   61,
- /*   360 */   696,  749,  750,  753,  789,  790,  795,  797,  840,  842,
- /*   370 */   810,  668,  817,  659,  819,  849,  854,  899,  643,  745,
- /*   380 */   956,  926,  916, 1523, 1529, 1511, 1391, 1521, 1458, 1525,
- /*   390 */  1519, 1520, 1423, 1414, 1436, 1526, 1425, 1531, 1426, 1537,
- /*   400 */  1553, 1431, 1427, 1444, 1496, 1522, 1429, 1505, 1509, 1510,
- /*   410 */  1512, 1452, 1468, 1535, 1447, 1570, 1567, 1551, 1477, 1433,
- /*   420 */  1513, 1550, 1514, 1502, 1538, 1455, 1483, 1559, 1564, 1566,
- /*   430 */  1473, 1481, 1565, 1524, 1568, 1571, 1569, 1572, 1528, 1561,
- /*   440 */  1574, 1530, 1562, 1575, 1577, 1578, 1576, 1580, 1582, 1581,
- /*   450 */  1583, 1585, 1584, 1486, 1587, 1588, 1515, 1586, 1590, 1489,
- /*   460 */  1589, 1591, 1592, 1593, 1594, 1596, 1598, 1589, 1599, 1600,
- /*   470 */  1602, 1601, 1604, 1605, 1607, 1608, 1609, 1610, 1612, 1613,
- /*   480 */  1615, 1614, 1518, 1516, 1527, 1532, 1533, 1618, 1616, 1637,
+ /*     0 */  1709, 1520, 1858, 1324, 1324,  277, 1374, 1469, 1602, 1712,
+ /*    10 */  1712, 1712,  273,    0,    0,  113, 1016, 1712, 1712, 1712,
+ /*    20 */  1712, 1712, 1712, 1712, 1712, 1712, 1712,   11,   11,  236,
+ /*    30 */   184,  277,  277,  277,  277,  277,  277,   93,  177,  270,
+ /*    40 */   363,  456,  549,  642,  735,  828,  848,  996, 1144, 1016,
+ /*    50 */  1016, 1016, 1016, 1016, 1016, 1016, 1016, 1016, 1016, 1016,
+ /*    60 */  1016, 1016, 1016, 1016, 1016, 1016, 1164, 1016, 1257, 1277,
+ /*    70 */  1277, 1490, 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712,
+ /*    80 */  1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712,
+ /*    90 */  1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712, 1712,
+ /*   100 */  1712, 1712, 1712, 1742, 1712, 1712, 1712, 1712, 1712, 1712,
+ /*   110 */  1712, 1712, 1712, 1712, 1712, 1712, 1712,  143,  162,  162,
+ /*   120 */   162,  162,  162,  204,  151,  416,  531,  648,  700,  531,
+ /*   130 */   486,  486,  531,  353,  353,  353,  353,  409,  279,   53,
+ /*   140 */  2009, 2009,  331,  331,  331,  329,  366,  329,  329,  597,
+ /*   150 */   597,  464,  474,  262,  681,  531,  531,  531,  531,  531,
+ /*   160 */   531,  531,  531,  531,  531,  531,  531,  531,  531,  531,
+ /*   170 */   531,  531,  531,  531,  531,  531,  531,  173,  485,  984,
+ /*   180 */   984,  576,  485,   19, 1022, 2009, 2009, 2009,  387,  250,
+ /*   190 */   250,  525,  502,  278,  552,  227,  480,  566,  531,  531,
+ /*   200 */   531,  531,  531,  531,  531,  531,  531,  531,  639,  531,
+ /*   210 */   531,  531,  531,  531,  531,  531,  531,  531,  531,  531,
+ /*   220 */   531,    2,    2,    2,  531,  531,  531,  531,  782,  531,
+ /*   230 */   531,  531,  744,  531,  531,  783,  531,  531,  531,  531,
+ /*   240 */   531,  531,  531,  531,  419,  682,  327,  370,  370,  370,
+ /*   250 */   370, 1029,  327,  327, 1024,  897,  856,  947, 1109,  706,
+ /*   260 */   706, 1143, 1109, 1109, 1143,  842,  945, 1118, 1136, 1136,
+ /*   270 */  1136,  706,  676,  400, 1047,  694, 1339, 1270, 1270, 1366,
+ /*   280 */  1366, 1270, 1305, 1389, 1369, 1278, 1401, 1401, 1401, 1401,
+ /*   290 */  1270, 1414, 1278, 1278, 1305, 1389, 1369, 1369, 1278, 1270,
+ /*   300 */  1414, 1298, 1385, 1270, 1414, 1432, 1270, 1414, 1270, 1414,
+ /*   310 */  1432, 1355, 1355, 1355, 1411, 1432, 1355, 1367, 1355, 1411,
+ /*   320 */  1355, 1355, 1432, 1392, 1392, 1432, 1365, 1396, 1365, 1396,
+ /*   330 */  1365, 1396, 1365, 1396, 1270, 1372, 1429, 1502, 1390, 1372,
+ /*   340 */  1517, 1270, 1397, 1390, 1410, 1413, 1278, 1528, 1532, 1549,
+ /*   350 */  1549, 1562, 1562, 1562, 2009, 2009, 2009, 2009, 2009, 2009,
+ /*   360 */  2009, 2009, 2009, 2009, 2009, 2009, 2009, 2009, 2009, 2009,
+ /*   370 */   570,  345,  686,  748,   50,  740, 1064, 1107,  469,  537,
+ /*   380 */  1042, 1146, 1162, 1154, 1201, 1202, 1203, 1208, 1209, 1127,
+ /*   390 */  1069, 1196, 1157, 1147, 1226, 1228, 1245,  775,  868, 1246,
+ /*   400 */  1247, 1191, 1151, 1585, 1589, 1587, 1456, 1600, 1527, 1601,
+ /*   410 */  1595, 1596, 1492, 1484, 1506, 1603, 1495, 1608, 1496, 1614,
+ /*   420 */  1635, 1508, 1497, 1521, 1580, 1606, 1505, 1592, 1593, 1597,
+ /*   430 */  1598, 1530, 1547, 1619, 1524, 1654, 1651, 1636, 1553, 1510,
+ /*   440 */  1594, 1634, 1599, 1588, 1623, 1535, 1564, 1642, 1649, 1652,
+ /*   450 */  1552, 1560, 1653, 1609, 1655, 1656, 1657, 1659, 1612, 1658,
+ /*   460 */  1660, 1616, 1648, 1664, 1550, 1668, 1538, 1670, 1671, 1669,
+ /*   470 */  1673, 1675, 1676, 1678, 1680, 1679, 1574, 1683, 1690, 1610,
+ /*   480 */  1682, 1695, 1586, 1698, 1691, 1698, 1693, 1643, 1661, 1646,
+ /*   490 */  1686, 1710, 1711, 1714, 1716, 1703, 1715, 1698, 1727, 1728,
+ /*   500 */  1729, 1730, 1731, 1732, 1734, 1743, 1736, 1737, 1740, 1744,
+ /*   510 */  1738, 1746, 1739, 1645, 1640, 1644, 1647, 1650, 1749, 1751,
+ /*   520 */  1772,
 };
-#define YY_REDUCE_COUNT (350)
-#define YY_REDUCE_MIN   (-225)
-#define YY_REDUCE_MAX   (1375)
+#define YY_REDUCE_COUNT (369)
+#define YY_REDUCE_MIN   (-237)
+#define YY_REDUCE_MAX   (1424)
 static const short yy_reduce_ofst[] = {
- /*     0 */  -137,  -31, 1104, 1023, 1081, -132,  -40,  -38,  223,  225,
- /*    10 */   698, -153,  -99, -225, -165,  386,  478,  843,  859, -139,
- /*    20 */   884,  117,  277,  844,  857,  964,  559,  561,  614,  918,
- /*    30 */  1009, 1089, 1098, -222, -222, -222, -222, -222, -222, -222,
- /*    40 */  -222, -222, -222, -222, -222, -222, -222, -222, -222, -222,
- /*    50 */  -222, -222, -222, -222, -222, -222, -222, -222, -222, -222,
- /*    60 */  -222, -222, -222, -222, -222,  329,  331,  497,  654,  656,
- /*    70 */   781,  891,  946, 1029, 1129, 1134, 1149, 1154, 1160, 1162,
- /*    80 */  1164, 1168, 1174, 1177, 1188, 1191, 1193, 1202, 1204, 1206,
- /*    90 */  1208, 1216, 1218, 1221, 1231, 1233, 1235, 1241, 1244, 1246,
- /*   100 */  1248, 1250, 1258, 1260, 1275, 1277, 1283, 1286, 1288, 1290,
- /*   110 */  1292, -222, -222, -222, -222, -222, -222, -222, -222, -222,
- /*   120 */  -115,  796, -156, -154, -141,   14,  242,  349,  242,  349,
- /*   130 */   -61, -222, -222, -222, -222, -222,  101,  101,  101,  332,
- /*   140 */   302,  384,  387, -170,  146,  344,  196,  196,   15,   11,
- /*   150 */   183,  235,  395,  355,  396,  406,  452,  457,  391,  459,
- /*   160 */   443,  447,  511,  495,  454,  512,  505,  571,  498,  532,
- /*   170 */   431,  435,  339,  455,  446,  508, -174, -116,  -97, -120,
- /*   180 */  -150,   64,  176,  330,  337,  509,  569,  611,  653,  673,
- /*   190 */   714,  717,  763,  771,  -34,  779,  786,  830,  846,  860,
- /*   200 */   866,  882,  883,  890,  892,  895,  902,  319,  368,  769,
- /*   210 */   915,  924,  925,  932,  755,  936,  945,  963,  782,  969,
- /*   220 */   974,  816,  977,   64,  982,  983, 1016, 1022, 1024, 1031,
- /*   230 */   870,  831,  913,  966,  973,  981,  984,  755,  913,  913,
- /*   240 */  1000, 1041, 1063, 1015, 1010, 1011,  985, 1034, 1057, 1019,
- /*   250 */  1086, 1080, 1085, 1093, 1095, 1096, 1067, 1048, 1082, 1099,
- /*   260 */  1137, 1050, 1150, 1156, 1077, 1088, 1180, 1120, 1132, 1169,
- /*   270 */  1170, 1178, 1181, 1195, 1210, 1225, 1243, 1197, 1209, 1173,
- /*   280 */  1190, 1226, 1238, 1223, 1267, 1272, 1199, 1207, 1282, 1285,
- /*   290 */  1269, 1293, 1295, 1296, 1300, 1289, 1294, 1297, 1299, 1287,
- /*   300 */  1301, 1302, 1303, 1306, 1304, 1307, 1308, 1310, 1242, 1245,
- /*   310 */  1311, 1268, 1270, 1273, 1278, 1274, 1279, 1280, 1284, 1333,
- /*   320 */  1271, 1337, 1281, 1309, 1305, 1312, 1314, 1316, 1344, 1347,
- /*   330 */  1359, 1361, 1368, 1370, 1371, 1291, 1313, 1317, 1355, 1352,
- /*   340 */  1353, 1354, 1356, 1363, 1350, 1357, 1362, 1366, 1367, 1375,
- /*   350 */  1365,
+ /*     0 */  -147,  171,  263,  -96,  358, -144, -149, -102,  124, -156,
+ /*    10 */   -98,  305,  401,  -57,  209, -237,  245,  -94,  -79,  189,
+ /*    20 */   375,  490,  493,  378,  303,  539,  542,  501,  503,  554,
+ /*    30 */   415,  526,  546,  557,  587,  593,  595, -234, -234, -234,
+ /*    40 */  -234, -234, -234, -234, -234, -234, -234, -234, -234, -234,
+ /*    50 */  -234, -234, -234, -234, -234, -234, -234, -234, -234, -234,
+ /*    60 */  -234, -234, -234, -234, -234, -234, -234, -234, -234, -234,
+ /*    70 */  -234,  -50,  335,  470,  633,  656,  658,  660,  675,  685,
+ /*    80 */   703,  727,  747,  750,  752,  754,  770,  788,  790,  793,
+ /*    90 */   795,  797,  800,  802,  804,  806,  813,  820,  829,  833,
+ /*   100 */   836,  838,  843,  845,  847,  849,  873,  891,  893,  916,
+ /*   110 */   918,  921,  936,  941,  944,  956,  961, -234, -234, -234,
+ /*   120 */  -234, -234, -234, -234, -234, -234,  463,  607, -176,   14,
+ /*   130 */  -139,   87, -137,  818,  925,  818,  925,  898, -234, -234,
+ /*   140 */  -234, -234, -166, -166, -166, -130, -131,  -82,  -54, -180,
+ /*   150 */   364,   41,  513,  509,  509,  117,  500,  789,  796,  646,
+ /*   160 */   192,  291,  644,  798,  120,  807,  543,  911,  920,  652,
+ /*   170 */   924,  922,  232,  698,  801,  971,   39,  220,  731,  442,
+ /*   180 */   902, -199,  979,  -43,  421,  896,  942,  605, -184, -126,
+ /*   190 */   155,  172,  281,  304,  377,  538,  650,  690,  699,  723,
+ /*   200 */   803,  839,  853,  919,  991, 1018, 1067, 1092,  951, 1111,
+ /*   210 */  1112, 1115, 1116, 1117, 1119, 1120, 1121, 1122, 1123, 1124,
+ /*   220 */  1125, 1012, 1096, 1097, 1128, 1129, 1130, 1131, 1070, 1135,
+ /*   230 */  1137, 1152, 1077, 1153, 1155, 1114, 1156,  304, 1158, 1172,
+ /*   240 */  1173, 1174, 1175, 1176, 1089, 1091, 1133, 1098, 1126, 1139,
+ /*   250 */  1140, 1070, 1133, 1133, 1170, 1163, 1186, 1103, 1168, 1138,
+ /*   260 */  1141, 1110, 1169, 1171, 1132, 1177, 1189, 1194, 1181, 1200,
+ /*   270 */  1204, 1166, 1145, 1178, 1187, 1232, 1142, 1231, 1233, 1149,
+ /*   280 */  1150, 1238, 1179, 1182, 1212, 1205, 1219, 1220, 1221, 1222,
+ /*   290 */  1258, 1266, 1223, 1224, 1206, 1211, 1237, 1239, 1230, 1269,
+ /*   300 */  1272, 1195, 1197, 1280, 1284, 1268, 1285, 1289, 1290, 1293,
+ /*   310 */  1274, 1286, 1287, 1288, 1282, 1294, 1292, 1297, 1300, 1296,
+ /*   320 */  1301, 1306, 1304, 1249, 1250, 1308, 1271, 1275, 1273, 1276,
+ /*   330 */  1279, 1281, 1283, 1302, 1334, 1307, 1243, 1267, 1318, 1322,
+ /*   340 */  1303, 1371, 1299, 1328, 1332, 1340, 1342, 1384, 1391, 1400,
+ /*   350 */  1403, 1407, 1408, 1409, 1311, 1312, 1310, 1405, 1402, 1412,
+ /*   360 */  1417, 1420, 1406, 1393, 1395, 1421, 1422, 1423, 1424, 1415,
 };
 static const YYACTIONTYPE yy_default[] = {
- /*     0 */  1389, 1389, 1389, 1261, 1046, 1151, 1261, 1261, 1261, 1261,
- /*    10 */  1046, 1181, 1181, 1312, 1077, 1046, 1046, 1046, 1046, 1046,
- /*    20 */  1046, 1260, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046,
- /*    30 */  1046, 1046, 1046, 1187, 1046, 1046, 1046, 1046, 1262, 1263,
- /*    40 */  1046, 1046, 1046, 1311, 1313, 1197, 1196, 1195, 1194, 1294,
- /*    50 */  1168, 1192, 1185, 1189, 1256, 1257, 1255, 1259, 1262, 1263,
- /*    60 */  1046, 1188, 1226, 1240, 1225, 1046, 1046, 1046, 1046, 1046,
- /*    70 */  1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046,
- /*    80 */  1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046,
- /*    90 */  1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046,
- /*   100 */  1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046,
- /*   110 */  1046, 1234, 1239, 1246, 1238, 1235, 1228, 1227, 1229, 1230,
- /*   120 */  1046, 1067, 1116, 1046, 1046, 1046, 1329, 1328, 1046, 1046,
- /*   130 */  1077, 1231, 1232, 1243, 1242, 1241, 1319, 1345, 1344, 1046,
- /*   140 */  1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046,
- /*   150 */  1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046,
- /*   160 */  1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1077,
- /*   170 */  1073, 1073, 1046, 1324, 1151, 1142, 1046, 1046, 1046, 1046,
- /*   180 */  1046, 1046, 1046, 1046, 1046, 1046, 1046, 1316, 1314, 1046,
- /*   190 */  1276, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046,
- /*   200 */  1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046,
- /*   210 */  1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1147, 1046,
- /*   220 */  1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1339,
- /*   230 */  1046, 1289, 1130, 1147, 1147, 1147, 1147, 1149, 1131, 1129,
- /*   240 */  1141, 1077, 1053, 1191, 1170, 1170, 1378, 1191, 1191, 1378,
- /*   250 */  1091, 1359, 1088, 1181, 1181, 1181, 1170, 1258, 1148, 1141,
- /*   260 */  1046, 1381, 1156, 1156, 1380, 1380, 1156, 1200, 1206, 1119,
- /*   270 */  1191, 1125, 1125, 1125, 1125, 1156, 1064, 1191, 1191, 1200,
- /*   280 */  1206, 1119, 1119, 1191, 1156, 1064, 1293, 1375, 1156, 1064,
- /*   290 */  1269, 1156, 1064, 1156, 1064, 1269, 1117, 1117, 1117, 1106,
- /*   300 */  1269, 1117, 1091, 1117, 1106, 1117, 1117, 1269, 1273, 1273,
- /*   310 */  1269, 1174, 1169, 1174, 1169, 1174, 1169, 1174, 1169, 1156,
- /*   320 */  1264, 1156, 1046, 1186, 1175, 1184, 1182, 1191, 1070, 1109,
- /*   330 */  1342, 1342, 1338, 1338, 1338, 1386, 1386, 1324, 1354, 1077,
- /*   340 */  1077, 1077, 1077, 1354, 1093, 1093, 1077, 1077, 1077, 1077,
- /*   350 */  1354, 1046, 1046, 1046, 1046, 1046, 1046, 1349, 1046, 1278,
- /*   360 */  1160, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046,
- /*   370 */  1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046,
- /*   380 */  1046, 1046, 1211, 1046, 1049, 1321, 1046, 1046, 1320, 1046,
- /*   390 */  1046, 1046, 1046, 1046, 1046, 1161, 1046, 1046, 1046, 1046,
- /*   400 */  1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046,
- /*   410 */  1046, 1046, 1046, 1046, 1377, 1046, 1046, 1046, 1046, 1046,
- /*   420 */  1046, 1292, 1291, 1046, 1046, 1158, 1046, 1046, 1046, 1046,
- /*   430 */  1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046,
- /*   440 */  1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046,
- /*   450 */  1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046,
- /*   460 */  1183, 1046, 1176, 1046, 1046, 1046, 1046, 1368, 1046, 1046,
- /*   470 */  1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046, 1046,
- /*   480 */  1046, 1363, 1133, 1213, 1046, 1212, 1216, 1046, 1058, 1046,
+ /*     0 */  1492, 1492, 1492, 1340, 1123, 1229, 1123, 1123, 1123, 1340,
+ /*    10 */  1340, 1340, 1123, 1259, 1259, 1391, 1154, 1123, 1123, 1123,
+ /*    20 */  1123, 1123, 1123, 1123, 1339, 1123, 1123, 1123, 1123, 1123,
+ /*    30 */  1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1265, 1123,
+ /*    40 */  1123, 1123, 1123, 1123, 1341, 1342, 1123, 1123, 1123, 1390,
+ /*    50 */  1392, 1275, 1274, 1273, 1272, 1373, 1246, 1270, 1263, 1267,
+ /*    60 */  1335, 1336, 1334, 1338, 1342, 1341, 1123, 1266, 1306, 1320,
+ /*    70 */  1305, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123,
+ /*    80 */  1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123,
+ /*    90 */  1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123,
+ /*   100 */  1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123,
+ /*   110 */  1123, 1123, 1123, 1123, 1123, 1123, 1123, 1314, 1319, 1325,
+ /*   120 */  1318, 1315, 1308, 1307, 1309, 1310, 1123, 1144, 1193, 1123,
+ /*   130 */  1123, 1123, 1123, 1409, 1408, 1123, 1123, 1154, 1311, 1312,
+ /*   140 */  1322, 1321, 1398, 1448, 1447, 1123, 1123, 1123, 1123, 1123,
+ /*   150 */  1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123,
+ /*   160 */  1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123,
+ /*   170 */  1123, 1123, 1123, 1123, 1123, 1123, 1123, 1154, 1150, 1300,
+ /*   180 */  1299, 1418, 1150, 1253, 1123, 1404, 1229, 1220, 1123, 1123,
+ /*   190 */  1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123,
+ /*   200 */  1123, 1395, 1393, 1123, 1355, 1123, 1123, 1123, 1123, 1123,
+ /*   210 */  1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123,
+ /*   220 */  1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123,
+ /*   230 */  1123, 1123, 1225, 1123, 1123, 1123, 1123, 1123, 1123, 1123,
+ /*   240 */  1123, 1123, 1123, 1442, 1123, 1368, 1207, 1225, 1225, 1225,
+ /*   250 */  1225, 1227, 1208, 1206, 1219, 1154, 1130, 1484, 1269, 1248,
+ /*   260 */  1248, 1481, 1269, 1269, 1481, 1168, 1462, 1165, 1259, 1259,
+ /*   270 */  1259, 1248, 1337, 1226, 1219, 1123, 1484, 1234, 1234, 1483,
+ /*   280 */  1483, 1234, 1278, 1284, 1196, 1269, 1202, 1202, 1202, 1202,
+ /*   290 */  1234, 1141, 1269, 1269, 1278, 1284, 1196, 1196, 1269, 1234,
+ /*   300 */  1141, 1372, 1478, 1234, 1141, 1348, 1234, 1141, 1234, 1141,
+ /*   310 */  1348, 1194, 1194, 1194, 1183, 1348, 1194, 1168, 1194, 1183,
+ /*   320 */  1194, 1194, 1348, 1352, 1352, 1348, 1252, 1247, 1252, 1247,
+ /*   330 */  1252, 1247, 1252, 1247, 1234, 1253, 1417, 1123, 1264, 1253,
+ /*   340 */  1343, 1234, 1123, 1264, 1262, 1260, 1269, 1147, 1186, 1445,
+ /*   350 */  1445, 1441, 1441, 1441, 1489, 1489, 1404, 1457, 1154, 1154,
+ /*   360 */  1154, 1154, 1457, 1170, 1170, 1154, 1154, 1154, 1154, 1457,
+ /*   370 */  1123, 1123, 1123, 1123, 1123, 1123, 1452, 1123, 1357, 1238,
+ /*   380 */  1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123,
+ /*   390 */  1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123,
+ /*   400 */  1123, 1123, 1289, 1123, 1126, 1401, 1123, 1123, 1399, 1123,
+ /*   410 */  1123, 1123, 1123, 1123, 1123, 1239, 1123, 1123, 1123, 1123,
+ /*   420 */  1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123,
+ /*   430 */  1123, 1123, 1123, 1123, 1480, 1123, 1123, 1123, 1123, 1123,
+ /*   440 */  1123, 1371, 1370, 1123, 1123, 1236, 1123, 1123, 1123, 1123,
+ /*   450 */  1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123,
+ /*   460 */  1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123,
+ /*   470 */  1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123,
+ /*   480 */  1123, 1123, 1123, 1261, 1123, 1416, 1123, 1123, 1123, 1123,
+ /*   490 */  1123, 1123, 1123, 1430, 1254, 1123, 1123, 1471, 1123, 1123,
+ /*   500 */  1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123, 1123,
+ /*   510 */  1123, 1123, 1466, 1210, 1291, 1123, 1290, 1294, 1123, 1135,
+ /*   520 */  1123,
 };
 /********** End of lemon-generated parsing tables *****************************/
 
@@ -142312,11 +146903,18 @@ static const YYCODETYPE yyFallback[] = {
    59,  /*    REPLACE => ID */
    59,  /*   RESTRICT => ID */
    59,  /*        ROW => ID */
+   59,  /*       ROWS => ID */
    59,  /*    TRIGGER => ID */
    59,  /*     VACUUM => ID */
    59,  /*       VIEW => ID */
    59,  /*    VIRTUAL => ID */
    59,  /*       WITH => ID */
+   59,  /*    CURRENT => ID */
+   59,  /*  FOLLOWING => ID */
+   59,  /*  PARTITION => ID */
+   59,  /*  PRECEDING => ID */
+   59,  /*      RANGE => ID */
+   59,  /*  UNBOUNDED => ID */
    59,  /*    REINDEX => ID */
    59,  /*     RENAME => ID */
    59,  /*   CTIME_KW => ID */
@@ -142483,185 +147081,207 @@ static const char *const yyTokenName[] = {
   /*   73 */ "REPLACE",
   /*   74 */ "RESTRICT",
   /*   75 */ "ROW",
-  /*   76 */ "TRIGGER",
-  /*   77 */ "VACUUM",
-  /*   78 */ "VIEW",
-  /*   79 */ "VIRTUAL",
-  /*   80 */ "WITH",
-  /*   81 */ "REINDEX",
-  /*   82 */ "RENAME",
-  /*   83 */ "CTIME_KW",
-  /*   84 */ "ANY",
-  /*   85 */ "BITAND",
-  /*   86 */ "BITOR",
-  /*   87 */ "LSHIFT",
-  /*   88 */ "RSHIFT",
-  /*   89 */ "PLUS",
-  /*   90 */ "MINUS",
-  /*   91 */ "STAR",
-  /*   92 */ "SLASH",
-  /*   93 */ "REM",
-  /*   94 */ "CONCAT",
-  /*   95 */ "COLLATE",
-  /*   96 */ "BITNOT",
-  /*   97 */ "ON",
-  /*   98 */ "INDEXED",
-  /*   99 */ "STRING",
-  /*  100 */ "JOIN_KW",
-  /*  101 */ "CONSTRAINT",
-  /*  102 */ "DEFAULT",
-  /*  103 */ "NULL",
-  /*  104 */ "PRIMARY",
-  /*  105 */ "UNIQUE",
-  /*  106 */ "CHECK",
-  /*  107 */ "REFERENCES",
-  /*  108 */ "AUTOINCR",
-  /*  109 */ "INSERT",
-  /*  110 */ "DELETE",
-  /*  111 */ "UPDATE",
-  /*  112 */ "SET",
-  /*  113 */ "DEFERRABLE",
-  /*  114 */ "FOREIGN",
-  /*  115 */ "DROP",
-  /*  116 */ "UNION",
-  /*  117 */ "ALL",
-  /*  118 */ "EXCEPT",
-  /*  119 */ "INTERSECT",
-  /*  120 */ "SELECT",
-  /*  121 */ "VALUES",
-  /*  122 */ "DISTINCT",
-  /*  123 */ "DOT",
-  /*  124 */ "FROM",
-  /*  125 */ "JOIN",
-  /*  126 */ "USING",
-  /*  127 */ "ORDER",
-  /*  128 */ "GROUP",
-  /*  129 */ "HAVING",
-  /*  130 */ "LIMIT",
-  /*  131 */ "WHERE",
-  /*  132 */ "INTO",
-  /*  133 */ "NOTHING",
-  /*  134 */ "FLOAT",
-  /*  135 */ "BLOB",
-  /*  136 */ "INTEGER",
-  /*  137 */ "VARIABLE",
-  /*  138 */ "CASE",
-  /*  139 */ "WHEN",
-  /*  140 */ "THEN",
-  /*  141 */ "ELSE",
-  /*  142 */ "INDEX",
-  /*  143 */ "ALTER",
-  /*  144 */ "ADD",
-  /*  145 */ "input",
-  /*  146 */ "cmdlist",
-  /*  147 */ "ecmd",
-  /*  148 */ "cmdx",
-  /*  149 */ "explain",
-  /*  150 */ "cmd",
-  /*  151 */ "transtype",
-  /*  152 */ "trans_opt",
-  /*  153 */ "nm",
-  /*  154 */ "savepoint_opt",
-  /*  155 */ "create_table",
-  /*  156 */ "create_table_args",
-  /*  157 */ "createkw",
-  /*  158 */ "temp",
-  /*  159 */ "ifnotexists",
-  /*  160 */ "dbnm",
-  /*  161 */ "columnlist",
-  /*  162 */ "conslist_opt",
-  /*  163 */ "table_options",
-  /*  164 */ "select",
-  /*  165 */ "columnname",
-  /*  166 */ "carglist",
-  /*  167 */ "typetoken",
-  /*  168 */ "typename",
-  /*  169 */ "signed",
-  /*  170 */ "plus_num",
-  /*  171 */ "minus_num",
-  /*  172 */ "scanpt",
-  /*  173 */ "ccons",
-  /*  174 */ "term",
-  /*  175 */ "expr",
-  /*  176 */ "onconf",
-  /*  177 */ "sortorder",
-  /*  178 */ "autoinc",
-  /*  179 */ "eidlist_opt",
-  /*  180 */ "refargs",
-  /*  181 */ "defer_subclause",
-  /*  182 */ "refarg",
-  /*  183 */ "refact",
-  /*  184 */ "init_deferred_pred_opt",
-  /*  185 */ "conslist",
-  /*  186 */ "tconscomma",
-  /*  187 */ "tcons",
-  /*  188 */ "sortlist",
-  /*  189 */ "eidlist",
-  /*  190 */ "defer_subclause_opt",
-  /*  191 */ "orconf",
-  /*  192 */ "resolvetype",
-  /*  193 */ "raisetype",
-  /*  194 */ "ifexists",
-  /*  195 */ "fullname",
-  /*  196 */ "selectnowith",
-  /*  197 */ "oneselect",
-  /*  198 */ "wqlist",
-  /*  199 */ "multiselect_op",
-  /*  200 */ "distinct",
-  /*  201 */ "selcollist",
-  /*  202 */ "from",
-  /*  203 */ "where_opt",
-  /*  204 */ "groupby_opt",
-  /*  205 */ "having_opt",
-  /*  206 */ "orderby_opt",
-  /*  207 */ "limit_opt",
-  /*  208 */ "values",
-  /*  209 */ "nexprlist",
-  /*  210 */ "exprlist",
-  /*  211 */ "sclp",
-  /*  212 */ "as",
-  /*  213 */ "seltablist",
-  /*  214 */ "stl_prefix",
-  /*  215 */ "joinop",
-  /*  216 */ "indexed_opt",
-  /*  217 */ "on_opt",
-  /*  218 */ "using_opt",
-  /*  219 */ "xfullname",
-  /*  220 */ "idlist",
-  /*  221 */ "with",
-  /*  222 */ "setlist",
-  /*  223 */ "insert_cmd",
-  /*  224 */ "idlist_opt",
-  /*  225 */ "upsert",
-  /*  226 */ "likeop",
-  /*  227 */ "between_op",
-  /*  228 */ "in_op",
-  /*  229 */ "paren_exprlist",
-  /*  230 */ "case_operand",
-  /*  231 */ "case_exprlist",
-  /*  232 */ "case_else",
-  /*  233 */ "uniqueflag",
-  /*  234 */ "collate",
-  /*  235 */ "nmnum",
-  /*  236 */ "trigger_decl",
-  /*  237 */ "trigger_cmd_list",
-  /*  238 */ "trigger_time",
-  /*  239 */ "trigger_event",
-  /*  240 */ "foreach_clause",
-  /*  241 */ "when_clause",
-  /*  242 */ "trigger_cmd",
-  /*  243 */ "trnm",
-  /*  244 */ "tridxby",
-  /*  245 */ "database_kw_opt",
-  /*  246 */ "key_opt",
-  /*  247 */ "add_column_fullname",
-  /*  248 */ "kwcolumn_opt",
-  /*  249 */ "create_vtab",
-  /*  250 */ "vtabarglist",
-  /*  251 */ "vtabarg",
-  /*  252 */ "vtabargtoken",
-  /*  253 */ "lp",
-  /*  254 */ "anylist",
+  /*   76 */ "ROWS",
+  /*   77 */ "TRIGGER",
+  /*   78 */ "VACUUM",
+  /*   79 */ "VIEW",
+  /*   80 */ "VIRTUAL",
+  /*   81 */ "WITH",
+  /*   82 */ "CURRENT",
+  /*   83 */ "FOLLOWING",
+  /*   84 */ "PARTITION",
+  /*   85 */ "PRECEDING",
+  /*   86 */ "RANGE",
+  /*   87 */ "UNBOUNDED",
+  /*   88 */ "REINDEX",
+  /*   89 */ "RENAME",
+  /*   90 */ "CTIME_KW",
+  /*   91 */ "ANY",
+  /*   92 */ "BITAND",
+  /*   93 */ "BITOR",
+  /*   94 */ "LSHIFT",
+  /*   95 */ "RSHIFT",
+  /*   96 */ "PLUS",
+  /*   97 */ "MINUS",
+  /*   98 */ "STAR",
+  /*   99 */ "SLASH",
+  /*  100 */ "REM",
+  /*  101 */ "CONCAT",
+  /*  102 */ "COLLATE",
+  /*  103 */ "BITNOT",
+  /*  104 */ "ON",
+  /*  105 */ "INDEXED",
+  /*  106 */ "STRING",
+  /*  107 */ "JOIN_KW",
+  /*  108 */ "CONSTRAINT",
+  /*  109 */ "DEFAULT",
+  /*  110 */ "NULL",
+  /*  111 */ "PRIMARY",
+  /*  112 */ "UNIQUE",
+  /*  113 */ "CHECK",
+  /*  114 */ "REFERENCES",
+  /*  115 */ "AUTOINCR",
+  /*  116 */ "INSERT",
+  /*  117 */ "DELETE",
+  /*  118 */ "UPDATE",
+  /*  119 */ "SET",
+  /*  120 */ "DEFERRABLE",
+  /*  121 */ "FOREIGN",
+  /*  122 */ "DROP",
+  /*  123 */ "UNION",
+  /*  124 */ "ALL",
+  /*  125 */ "EXCEPT",
+  /*  126 */ "INTERSECT",
+  /*  127 */ "SELECT",
+  /*  128 */ "VALUES",
+  /*  129 */ "DISTINCT",
+  /*  130 */ "DOT",
+  /*  131 */ "FROM",
+  /*  132 */ "JOIN",
+  /*  133 */ "USING",
+  /*  134 */ "ORDER",
+  /*  135 */ "GROUP",
+  /*  136 */ "HAVING",
+  /*  137 */ "LIMIT",
+  /*  138 */ "WHERE",
+  /*  139 */ "INTO",
+  /*  140 */ "NOTHING",
+  /*  141 */ "FLOAT",
+  /*  142 */ "BLOB",
+  /*  143 */ "INTEGER",
+  /*  144 */ "VARIABLE",
+  /*  145 */ "CASE",
+  /*  146 */ "WHEN",
+  /*  147 */ "THEN",
+  /*  148 */ "ELSE",
+  /*  149 */ "INDEX",
+  /*  150 */ "ALTER",
+  /*  151 */ "ADD",
+  /*  152 */ "WINDOW",
+  /*  153 */ "OVER",
+  /*  154 */ "FILTER",
+  /*  155 */ "input",
+  /*  156 */ "cmdlist",
+  /*  157 */ "ecmd",
+  /*  158 */ "cmdx",
+  /*  159 */ "explain",
+  /*  160 */ "cmd",
+  /*  161 */ "transtype",
+  /*  162 */ "trans_opt",
+  /*  163 */ "nm",
+  /*  164 */ "savepoint_opt",
+  /*  165 */ "create_table",
+  /*  166 */ "create_table_args",
+  /*  167 */ "createkw",
+  /*  168 */ "temp",
+  /*  169 */ "ifnotexists",
+  /*  170 */ "dbnm",
+  /*  171 */ "columnlist",
+  /*  172 */ "conslist_opt",
+  /*  173 */ "table_options",
+  /*  174 */ "select",
+  /*  175 */ "columnname",
+  /*  176 */ "carglist",
+  /*  177 */ "typetoken",
+  /*  178 */ "typename",
+  /*  179 */ "signed",
+  /*  180 */ "plus_num",
+  /*  181 */ "minus_num",
+  /*  182 */ "scanpt",
+  /*  183 */ "ccons",
+  /*  184 */ "term",
+  /*  185 */ "expr",
+  /*  186 */ "onconf",
+  /*  187 */ "sortorder",
+  /*  188 */ "autoinc",
+  /*  189 */ "eidlist_opt",
+  /*  190 */ "refargs",
+  /*  191 */ "defer_subclause",
+  /*  192 */ "refarg",
+  /*  193 */ "refact",
+  /*  194 */ "init_deferred_pred_opt",
+  /*  195 */ "conslist",
+  /*  196 */ "tconscomma",
+  /*  197 */ "tcons",
+  /*  198 */ "sortlist",
+  /*  199 */ "eidlist",
+  /*  200 */ "defer_subclause_opt",
+  /*  201 */ "orconf",
+  /*  202 */ "resolvetype",
+  /*  203 */ "raisetype",
+  /*  204 */ "ifexists",
+  /*  205 */ "fullname",
+  /*  206 */ "selectnowith",
+  /*  207 */ "oneselect",
+  /*  208 */ "wqlist",
+  /*  209 */ "multiselect_op",
+  /*  210 */ "distinct",
+  /*  211 */ "selcollist",
+  /*  212 */ "from",
+  /*  213 */ "where_opt",
+  /*  214 */ "groupby_opt",
+  /*  215 */ "having_opt",
+  /*  216 */ "orderby_opt",
+  /*  217 */ "limit_opt",
+  /*  218 */ "window_clause",
+  /*  219 */ "values",
+  /*  220 */ "nexprlist",
+  /*  221 */ "sclp",
+  /*  222 */ "as",
+  /*  223 */ "seltablist",
+  /*  224 */ "stl_prefix",
+  /*  225 */ "joinop",
+  /*  226 */ "indexed_opt",
+  /*  227 */ "on_opt",
+  /*  228 */ "using_opt",
+  /*  229 */ "exprlist",
+  /*  230 */ "xfullname",
+  /*  231 */ "idlist",
+  /*  232 */ "with",
+  /*  233 */ "setlist",
+  /*  234 */ "insert_cmd",
+  /*  235 */ "idlist_opt",
+  /*  236 */ "upsert",
+  /*  237 */ "over_clause",
+  /*  238 */ "likeop",
+  /*  239 */ "between_op",
+  /*  240 */ "in_op",
+  /*  241 */ "paren_exprlist",
+  /*  242 */ "case_operand",
+  /*  243 */ "case_exprlist",
+  /*  244 */ "case_else",
+  /*  245 */ "uniqueflag",
+  /*  246 */ "collate",
+  /*  247 */ "nmnum",
+  /*  248 */ "trigger_decl",
+  /*  249 */ "trigger_cmd_list",
+  /*  250 */ "trigger_time",
+  /*  251 */ "trigger_event",
+  /*  252 */ "foreach_clause",
+  /*  253 */ "when_clause",
+  /*  254 */ "trigger_cmd",
+  /*  255 */ "trnm",
+  /*  256 */ "tridxby",
+  /*  257 */ "database_kw_opt",
+  /*  258 */ "key_opt",
+  /*  259 */ "add_column_fullname",
+  /*  260 */ "kwcolumn_opt",
+  /*  261 */ "create_vtab",
+  /*  262 */ "vtabarglist",
+  /*  263 */ "vtabarg",
+  /*  264 */ "vtabargtoken",
+  /*  265 */ "lp",
+  /*  266 */ "anylist",
+  /*  267 */ "windowdefn_list",
+  /*  268 */ "windowdefn",
+  /*  269 */ "window",
+  /*  270 */ "frame_opt",
+  /*  271 */ "part_opt",
+  /*  272 */ "filter_opt",
+  /*  273 */ "range_or_rows",
+  /*  274 */ "frame_bound",
+  /*  275 */ "frame_bound_s",
+  /*  276 */ "frame_bound_e",
 };
 #endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */
 
@@ -142757,259 +147377,285 @@ static const char *const yyRuleName[] = {
  /*  85 */ "multiselect_op ::= UNION ALL",
  /*  86 */ "multiselect_op ::= EXCEPT|INTERSECT",
  /*  87 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
- /*  88 */ "values ::= VALUES LP nexprlist RP",
- /*  89 */ "values ::= values COMMA LP exprlist RP",
- /*  90 */ "distinct ::= DISTINCT",
- /*  91 */ "distinct ::= ALL",
- /*  92 */ "distinct ::=",
- /*  93 */ "sclp ::=",
- /*  94 */ "selcollist ::= sclp scanpt expr scanpt as",
- /*  95 */ "selcollist ::= sclp scanpt STAR",
- /*  96 */ "selcollist ::= sclp scanpt nm DOT STAR",
- /*  97 */ "as ::= AS nm",
- /*  98 */ "as ::=",
- /*  99 */ "from ::=",
- /* 100 */ "from ::= FROM seltablist",
- /* 101 */ "stl_prefix ::= seltablist joinop",
- /* 102 */ "stl_prefix ::=",
- /* 103 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt",
- /* 104 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt",
- /* 105 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt",
- /* 106 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt",
- /* 107 */ "dbnm ::=",
- /* 108 */ "dbnm ::= DOT nm",
- /* 109 */ "fullname ::= nm",
- /* 110 */ "fullname ::= nm DOT nm",
- /* 111 */ "xfullname ::= nm",
- /* 112 */ "xfullname ::= nm DOT nm",
- /* 113 */ "xfullname ::= nm DOT nm AS nm",
- /* 114 */ "xfullname ::= nm AS nm",
- /* 115 */ "joinop ::= COMMA|JOIN",
- /* 116 */ "joinop ::= JOIN_KW JOIN",
- /* 117 */ "joinop ::= JOIN_KW nm JOIN",
- /* 118 */ "joinop ::= JOIN_KW nm nm JOIN",
- /* 119 */ "on_opt ::= ON expr",
- /* 120 */ "on_opt ::=",
- /* 121 */ "indexed_opt ::=",
- /* 122 */ "indexed_opt ::= INDEXED BY nm",
- /* 123 */ "indexed_opt ::= NOT INDEXED",
- /* 124 */ "using_opt ::= USING LP idlist RP",
- /* 125 */ "using_opt ::=",
- /* 126 */ "orderby_opt ::=",
- /* 127 */ "orderby_opt ::= ORDER BY sortlist",
- /* 128 */ "sortlist ::= sortlist COMMA expr sortorder",
- /* 129 */ "sortlist ::= expr sortorder",
- /* 130 */ "sortorder ::= ASC",
- /* 131 */ "sortorder ::= DESC",
- /* 132 */ "sortorder ::=",
- /* 133 */ "groupby_opt ::=",
- /* 134 */ "groupby_opt ::= GROUP BY nexprlist",
- /* 135 */ "having_opt ::=",
- /* 136 */ "having_opt ::= HAVING expr",
- /* 137 */ "limit_opt ::=",
- /* 138 */ "limit_opt ::= LIMIT expr",
- /* 139 */ "limit_opt ::= LIMIT expr OFFSET expr",
- /* 140 */ "limit_opt ::= LIMIT expr COMMA expr",
- /* 141 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt",
- /* 142 */ "where_opt ::=",
- /* 143 */ "where_opt ::= WHERE expr",
- /* 144 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt",
- /* 145 */ "setlist ::= setlist COMMA nm EQ expr",
- /* 146 */ "setlist ::= setlist COMMA LP idlist RP EQ expr",
- /* 147 */ "setlist ::= nm EQ expr",
- /* 148 */ "setlist ::= LP idlist RP EQ expr",
- /* 149 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert",
- /* 150 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES",
- /* 151 */ "upsert ::=",
- /* 152 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt",
- /* 153 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING",
- /* 154 */ "upsert ::= ON CONFLICT DO NOTHING",
- /* 155 */ "insert_cmd ::= INSERT orconf",
- /* 156 */ "insert_cmd ::= REPLACE",
- /* 157 */ "idlist_opt ::=",
- /* 158 */ "idlist_opt ::= LP idlist RP",
- /* 159 */ "idlist ::= idlist COMMA nm",
- /* 160 */ "idlist ::= nm",
- /* 161 */ "expr ::= LP expr RP",
- /* 162 */ "expr ::= ID|INDEXED",
- /* 163 */ "expr ::= JOIN_KW",
- /* 164 */ "expr ::= nm DOT nm",
- /* 165 */ "expr ::= nm DOT nm DOT nm",
- /* 166 */ "term ::= NULL|FLOAT|BLOB",
- /* 167 */ "term ::= STRING",
- /* 168 */ "term ::= INTEGER",
- /* 169 */ "expr ::= VARIABLE",
- /* 170 */ "expr ::= expr COLLATE ID|STRING",
- /* 171 */ "expr ::= CAST LP expr AS typetoken RP",
- /* 172 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
- /* 173 */ "expr ::= ID|INDEXED LP STAR RP",
- /* 174 */ "term ::= CTIME_KW",
- /* 175 */ "expr ::= LP nexprlist COMMA expr RP",
- /* 176 */ "expr ::= expr AND expr",
- /* 177 */ "expr ::= expr OR expr",
- /* 178 */ "expr ::= expr LT|GT|GE|LE expr",
- /* 179 */ "expr ::= expr EQ|NE expr",
- /* 180 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
- /* 181 */ "expr ::= expr PLUS|MINUS expr",
- /* 182 */ "expr ::= expr STAR|SLASH|REM expr",
- /* 183 */ "expr ::= expr CONCAT expr",
- /* 184 */ "likeop ::= NOT LIKE_KW|MATCH",
- /* 185 */ "expr ::= expr likeop expr",
- /* 186 */ "expr ::= expr likeop expr ESCAPE expr",
- /* 187 */ "expr ::= expr ISNULL|NOTNULL",
- /* 188 */ "expr ::= expr NOT NULL",
- /* 189 */ "expr ::= expr IS expr",
- /* 190 */ "expr ::= expr IS NOT expr",
- /* 191 */ "expr ::= NOT expr",
- /* 192 */ "expr ::= BITNOT expr",
- /* 193 */ "expr ::= MINUS expr",
- /* 194 */ "expr ::= PLUS expr",
- /* 195 */ "between_op ::= BETWEEN",
- /* 196 */ "between_op ::= NOT BETWEEN",
- /* 197 */ "expr ::= expr between_op expr AND expr",
- /* 198 */ "in_op ::= IN",
- /* 199 */ "in_op ::= NOT IN",
- /* 200 */ "expr ::= expr in_op LP exprlist RP",
- /* 201 */ "expr ::= LP select RP",
- /* 202 */ "expr ::= expr in_op LP select RP",
- /* 203 */ "expr ::= expr in_op nm dbnm paren_exprlist",
- /* 204 */ "expr ::= EXISTS LP select RP",
- /* 205 */ "expr ::= CASE case_operand case_exprlist case_else END",
- /* 206 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
- /* 207 */ "case_exprlist ::= WHEN expr THEN expr",
- /* 208 */ "case_else ::= ELSE expr",
- /* 209 */ "case_else ::=",
- /* 210 */ "case_operand ::= expr",
- /* 211 */ "case_operand ::=",
- /* 212 */ "exprlist ::=",
- /* 213 */ "nexprlist ::= nexprlist COMMA expr",
- /* 214 */ "nexprlist ::= expr",
- /* 215 */ "paren_exprlist ::=",
- /* 216 */ "paren_exprlist ::= LP exprlist RP",
- /* 217 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
- /* 218 */ "uniqueflag ::= UNIQUE",
- /* 219 */ "uniqueflag ::=",
- /* 220 */ "eidlist_opt ::=",
- /* 221 */ "eidlist_opt ::= LP eidlist RP",
- /* 222 */ "eidlist ::= eidlist COMMA nm collate sortorder",
- /* 223 */ "eidlist ::= nm collate sortorder",
- /* 224 */ "collate ::=",
- /* 225 */ "collate ::= COLLATE ID|STRING",
- /* 226 */ "cmd ::= DROP INDEX ifexists fullname",
- /* 227 */ "cmd ::= VACUUM",
- /* 228 */ "cmd ::= VACUUM nm",
- /* 229 */ "cmd ::= PRAGMA nm dbnm",
- /* 230 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
- /* 231 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
- /* 232 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
- /* 233 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
- /* 234 */ "plus_num ::= PLUS INTEGER|FLOAT",
- /* 235 */ "minus_num ::= MINUS INTEGER|FLOAT",
- /* 236 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
- /* 237 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
- /* 238 */ "trigger_time ::= BEFORE|AFTER",
- /* 239 */ "trigger_time ::= INSTEAD OF",
- /* 240 */ "trigger_time ::=",
- /* 241 */ "trigger_event ::= DELETE|INSERT",
- /* 242 */ "trigger_event ::= UPDATE",
- /* 243 */ "trigger_event ::= UPDATE OF idlist",
- /* 244 */ "when_clause ::=",
- /* 245 */ "when_clause ::= WHEN expr",
- /* 246 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
- /* 247 */ "trigger_cmd_list ::= trigger_cmd SEMI",
- /* 248 */ "trnm ::= nm DOT nm",
- /* 249 */ "tridxby ::= INDEXED BY nm",
- /* 250 */ "tridxby ::= NOT INDEXED",
- /* 251 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt",
- /* 252 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt",
- /* 253 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt",
- /* 254 */ "trigger_cmd ::= scanpt select scanpt",
- /* 255 */ "expr ::= RAISE LP IGNORE RP",
- /* 256 */ "expr ::= RAISE LP raisetype COMMA nm RP",
- /* 257 */ "raisetype ::= ROLLBACK",
- /* 258 */ "raisetype ::= ABORT",
- /* 259 */ "raisetype ::= FAIL",
- /* 260 */ "cmd ::= DROP TRIGGER ifexists fullname",
- /* 261 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
- /* 262 */ "cmd ::= DETACH database_kw_opt expr",
- /* 263 */ "key_opt ::=",
- /* 264 */ "key_opt ::= KEY expr",
- /* 265 */ "cmd ::= REINDEX",
- /* 266 */ "cmd ::= REINDEX nm dbnm",
- /* 267 */ "cmd ::= ANALYZE",
- /* 268 */ "cmd ::= ANALYZE nm dbnm",
- /* 269 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
- /* 270 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist",
- /* 271 */ "add_column_fullname ::= fullname",
- /* 272 */ "cmd ::= create_vtab",
- /* 273 */ "cmd ::= create_vtab LP vtabarglist RP",
- /* 274 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
- /* 275 */ "vtabarg ::=",
- /* 276 */ "vtabargtoken ::= ANY",
- /* 277 */ "vtabargtoken ::= lp anylist RP",
- /* 278 */ "lp ::= LP",
- /* 279 */ "with ::= WITH wqlist",
- /* 280 */ "with ::= WITH RECURSIVE wqlist",
- /* 281 */ "wqlist ::= nm eidlist_opt AS LP select RP",
- /* 282 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP",
- /* 283 */ "input ::= cmdlist",
- /* 284 */ "cmdlist ::= cmdlist ecmd",
- /* 285 */ "cmdlist ::= ecmd",
- /* 286 */ "ecmd ::= SEMI",
- /* 287 */ "ecmd ::= cmdx SEMI",
- /* 288 */ "ecmd ::= explain cmdx",
- /* 289 */ "trans_opt ::=",
- /* 290 */ "trans_opt ::= TRANSACTION",
- /* 291 */ "trans_opt ::= TRANSACTION nm",
- /* 292 */ "savepoint_opt ::= SAVEPOINT",
- /* 293 */ "savepoint_opt ::=",
- /* 294 */ "cmd ::= create_table create_table_args",
- /* 295 */ "columnlist ::= columnlist COMMA columnname carglist",
- /* 296 */ "columnlist ::= columnname carglist",
- /* 297 */ "nm ::= ID|INDEXED",
- /* 298 */ "nm ::= STRING",
- /* 299 */ "nm ::= JOIN_KW",
- /* 300 */ "typetoken ::= typename",
- /* 301 */ "typename ::= ID|STRING",
- /* 302 */ "signed ::= plus_num",
- /* 303 */ "signed ::= minus_num",
- /* 304 */ "carglist ::= carglist ccons",
- /* 305 */ "carglist ::=",
- /* 306 */ "ccons ::= NULL onconf",
- /* 307 */ "conslist_opt ::= COMMA conslist",
- /* 308 */ "conslist ::= conslist tconscomma tcons",
- /* 309 */ "conslist ::= tcons",
- /* 310 */ "tconscomma ::=",
- /* 311 */ "defer_subclause_opt ::= defer_subclause",
- /* 312 */ "resolvetype ::= raisetype",
- /* 313 */ "selectnowith ::= oneselect",
- /* 314 */ "oneselect ::= values",
- /* 315 */ "sclp ::= selcollist COMMA",
- /* 316 */ "as ::= ID|STRING",
- /* 317 */ "expr ::= term",
- /* 318 */ "likeop ::= LIKE_KW|MATCH",
- /* 319 */ "exprlist ::= nexprlist",
- /* 320 */ "nmnum ::= plus_num",
- /* 321 */ "nmnum ::= nm",
- /* 322 */ "nmnum ::= ON",
- /* 323 */ "nmnum ::= DELETE",
- /* 324 */ "nmnum ::= DEFAULT",
- /* 325 */ "plus_num ::= INTEGER|FLOAT",
- /* 326 */ "foreach_clause ::=",
- /* 327 */ "foreach_clause ::= FOR EACH ROW",
- /* 328 */ "trnm ::= nm",
- /* 329 */ "tridxby ::=",
- /* 330 */ "database_kw_opt ::= DATABASE",
- /* 331 */ "database_kw_opt ::=",
- /* 332 */ "kwcolumn_opt ::=",
- /* 333 */ "kwcolumn_opt ::= COLUMNKW",
- /* 334 */ "vtabarglist ::= vtabarg",
- /* 335 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
- /* 336 */ "vtabarg ::= vtabarg vtabargtoken",
- /* 337 */ "anylist ::=",
- /* 338 */ "anylist ::= anylist LP anylist RP",
- /* 339 */ "anylist ::= anylist ANY",
- /* 340 */ "with ::=",
+ /*  88 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt",
+ /*  89 */ "values ::= VALUES LP nexprlist RP",
+ /*  90 */ "values ::= values COMMA LP nexprlist RP",
+ /*  91 */ "distinct ::= DISTINCT",
+ /*  92 */ "distinct ::= ALL",
+ /*  93 */ "distinct ::=",
+ /*  94 */ "sclp ::=",
+ /*  95 */ "selcollist ::= sclp scanpt expr scanpt as",
+ /*  96 */ "selcollist ::= sclp scanpt STAR",
+ /*  97 */ "selcollist ::= sclp scanpt nm DOT STAR",
+ /*  98 */ "as ::= AS nm",
+ /*  99 */ "as ::=",
+ /* 100 */ "from ::=",
+ /* 101 */ "from ::= FROM seltablist",
+ /* 102 */ "stl_prefix ::= seltablist joinop",
+ /* 103 */ "stl_prefix ::=",
+ /* 104 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt",
+ /* 105 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt",
+ /* 106 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt",
+ /* 107 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt",
+ /* 108 */ "dbnm ::=",
+ /* 109 */ "dbnm ::= DOT nm",
+ /* 110 */ "fullname ::= nm",
+ /* 111 */ "fullname ::= nm DOT nm",
+ /* 112 */ "xfullname ::= nm",
+ /* 113 */ "xfullname ::= nm DOT nm",
+ /* 114 */ "xfullname ::= nm DOT nm AS nm",
+ /* 115 */ "xfullname ::= nm AS nm",
+ /* 116 */ "joinop ::= COMMA|JOIN",
+ /* 117 */ "joinop ::= JOIN_KW JOIN",
+ /* 118 */ "joinop ::= JOIN_KW nm JOIN",
+ /* 119 */ "joinop ::= JOIN_KW nm nm JOIN",
+ /* 120 */ "on_opt ::= ON expr",
+ /* 121 */ "on_opt ::=",
+ /* 122 */ "indexed_opt ::=",
+ /* 123 */ "indexed_opt ::= INDEXED BY nm",
+ /* 124 */ "indexed_opt ::= NOT INDEXED",
+ /* 125 */ "using_opt ::= USING LP idlist RP",
+ /* 126 */ "using_opt ::=",
+ /* 127 */ "orderby_opt ::=",
+ /* 128 */ "orderby_opt ::= ORDER BY sortlist",
+ /* 129 */ "sortlist ::= sortlist COMMA expr sortorder",
+ /* 130 */ "sortlist ::= expr sortorder",
+ /* 131 */ "sortorder ::= ASC",
+ /* 132 */ "sortorder ::= DESC",
+ /* 133 */ "sortorder ::=",
+ /* 134 */ "groupby_opt ::=",
+ /* 135 */ "groupby_opt ::= GROUP BY nexprlist",
+ /* 136 */ "having_opt ::=",
+ /* 137 */ "having_opt ::= HAVING expr",
+ /* 138 */ "limit_opt ::=",
+ /* 139 */ "limit_opt ::= LIMIT expr",
+ /* 140 */ "limit_opt ::= LIMIT expr OFFSET expr",
+ /* 141 */ "limit_opt ::= LIMIT expr COMMA expr",
+ /* 142 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt",
+ /* 143 */ "where_opt ::=",
+ /* 144 */ "where_opt ::= WHERE expr",
+ /* 145 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt",
+ /* 146 */ "setlist ::= setlist COMMA nm EQ expr",
+ /* 147 */ "setlist ::= setlist COMMA LP idlist RP EQ expr",
+ /* 148 */ "setlist ::= nm EQ expr",
+ /* 149 */ "setlist ::= LP idlist RP EQ expr",
+ /* 150 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert",
+ /* 151 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES",
+ /* 152 */ "upsert ::=",
+ /* 153 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt",
+ /* 154 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING",
+ /* 155 */ "upsert ::= ON CONFLICT DO NOTHING",
+ /* 156 */ "insert_cmd ::= INSERT orconf",
+ /* 157 */ "insert_cmd ::= REPLACE",
+ /* 158 */ "idlist_opt ::=",
+ /* 159 */ "idlist_opt ::= LP idlist RP",
+ /* 160 */ "idlist ::= idlist COMMA nm",
+ /* 161 */ "idlist ::= nm",
+ /* 162 */ "expr ::= LP expr RP",
+ /* 163 */ "expr ::= ID|INDEXED",
+ /* 164 */ "expr ::= JOIN_KW",
+ /* 165 */ "expr ::= nm DOT nm",
+ /* 166 */ "expr ::= nm DOT nm DOT nm",
+ /* 167 */ "term ::= NULL|FLOAT|BLOB",
+ /* 168 */ "term ::= STRING",
+ /* 169 */ "term ::= INTEGER",
+ /* 170 */ "expr ::= VARIABLE",
+ /* 171 */ "expr ::= expr COLLATE ID|STRING",
+ /* 172 */ "expr ::= CAST LP expr AS typetoken RP",
+ /* 173 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
+ /* 174 */ "expr ::= ID|INDEXED LP STAR RP",
+ /* 175 */ "expr ::= ID|INDEXED LP distinct exprlist RP over_clause",
+ /* 176 */ "expr ::= ID|INDEXED LP STAR RP over_clause",
+ /* 177 */ "term ::= CTIME_KW",
+ /* 178 */ "expr ::= LP nexprlist COMMA expr RP",
+ /* 179 */ "expr ::= expr AND expr",
+ /* 180 */ "expr ::= expr OR expr",
+ /* 181 */ "expr ::= expr LT|GT|GE|LE expr",
+ /* 182 */ "expr ::= expr EQ|NE expr",
+ /* 183 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
+ /* 184 */ "expr ::= expr PLUS|MINUS expr",
+ /* 185 */ "expr ::= expr STAR|SLASH|REM expr",
+ /* 186 */ "expr ::= expr CONCAT expr",
+ /* 187 */ "likeop ::= NOT LIKE_KW|MATCH",
+ /* 188 */ "expr ::= expr likeop expr",
+ /* 189 */ "expr ::= expr likeop expr ESCAPE expr",
+ /* 190 */ "expr ::= expr ISNULL|NOTNULL",
+ /* 191 */ "expr ::= expr NOT NULL",
+ /* 192 */ "expr ::= expr IS expr",
+ /* 193 */ "expr ::= expr IS NOT expr",
+ /* 194 */ "expr ::= NOT expr",
+ /* 195 */ "expr ::= BITNOT expr",
+ /* 196 */ "expr ::= PLUS|MINUS expr",
+ /* 197 */ "between_op ::= BETWEEN",
+ /* 198 */ "between_op ::= NOT BETWEEN",
+ /* 199 */ "expr ::= expr between_op expr AND expr",
+ /* 200 */ "in_op ::= IN",
+ /* 201 */ "in_op ::= NOT IN",
+ /* 202 */ "expr ::= expr in_op LP exprlist RP",
+ /* 203 */ "expr ::= LP select RP",
+ /* 204 */ "expr ::= expr in_op LP select RP",
+ /* 205 */ "expr ::= expr in_op nm dbnm paren_exprlist",
+ /* 206 */ "expr ::= EXISTS LP select RP",
+ /* 207 */ "expr ::= CASE case_operand case_exprlist case_else END",
+ /* 208 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
+ /* 209 */ "case_exprlist ::= WHEN expr THEN expr",
+ /* 210 */ "case_else ::= ELSE expr",
+ /* 211 */ "case_else ::=",
+ /* 212 */ "case_operand ::= expr",
+ /* 213 */ "case_operand ::=",
+ /* 214 */ "exprlist ::=",
+ /* 215 */ "nexprlist ::= nexprlist COMMA expr",
+ /* 216 */ "nexprlist ::= expr",
+ /* 217 */ "paren_exprlist ::=",
+ /* 218 */ "paren_exprlist ::= LP exprlist RP",
+ /* 219 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
+ /* 220 */ "uniqueflag ::= UNIQUE",
+ /* 221 */ "uniqueflag ::=",
+ /* 222 */ "eidlist_opt ::=",
+ /* 223 */ "eidlist_opt ::= LP eidlist RP",
+ /* 224 */ "eidlist ::= eidlist COMMA nm collate sortorder",
+ /* 225 */ "eidlist ::= nm collate sortorder",
+ /* 226 */ "collate ::=",
+ /* 227 */ "collate ::= COLLATE ID|STRING",
+ /* 228 */ "cmd ::= DROP INDEX ifexists fullname",
+ /* 229 */ "cmd ::= VACUUM",
+ /* 230 */ "cmd ::= VACUUM nm",
+ /* 231 */ "cmd ::= PRAGMA nm dbnm",
+ /* 232 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
+ /* 233 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
+ /* 234 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
+ /* 235 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
+ /* 236 */ "plus_num ::= PLUS INTEGER|FLOAT",
+ /* 237 */ "minus_num ::= MINUS INTEGER|FLOAT",
+ /* 238 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
+ /* 239 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
+ /* 240 */ "trigger_time ::= BEFORE|AFTER",
+ /* 241 */ "trigger_time ::= INSTEAD OF",
+ /* 242 */ "trigger_time ::=",
+ /* 243 */ "trigger_event ::= DELETE|INSERT",
+ /* 244 */ "trigger_event ::= UPDATE",
+ /* 245 */ "trigger_event ::= UPDATE OF idlist",
+ /* 246 */ "when_clause ::=",
+ /* 247 */ "when_clause ::= WHEN expr",
+ /* 248 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
+ /* 249 */ "trigger_cmd_list ::= trigger_cmd SEMI",
+ /* 250 */ "trnm ::= nm DOT nm",
+ /* 251 */ "tridxby ::= INDEXED BY nm",
+ /* 252 */ "tridxby ::= NOT INDEXED",
+ /* 253 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt",
+ /* 254 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt",
+ /* 255 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt",
+ /* 256 */ "trigger_cmd ::= scanpt select scanpt",
+ /* 257 */ "expr ::= RAISE LP IGNORE RP",
+ /* 258 */ "expr ::= RAISE LP raisetype COMMA nm RP",
+ /* 259 */ "raisetype ::= ROLLBACK",
+ /* 260 */ "raisetype ::= ABORT",
+ /* 261 */ "raisetype ::= FAIL",
+ /* 262 */ "cmd ::= DROP TRIGGER ifexists fullname",
+ /* 263 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
+ /* 264 */ "cmd ::= DETACH database_kw_opt expr",
+ /* 265 */ "key_opt ::=",
+ /* 266 */ "key_opt ::= KEY expr",
+ /* 267 */ "cmd ::= REINDEX",
+ /* 268 */ "cmd ::= REINDEX nm dbnm",
+ /* 269 */ "cmd ::= ANALYZE",
+ /* 270 */ "cmd ::= ANALYZE nm dbnm",
+ /* 271 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
+ /* 272 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist",
+ /* 273 */ "add_column_fullname ::= fullname",
+ /* 274 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm",
+ /* 275 */ "cmd ::= create_vtab",
+ /* 276 */ "cmd ::= create_vtab LP vtabarglist RP",
+ /* 277 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
+ /* 278 */ "vtabarg ::=",
+ /* 279 */ "vtabargtoken ::= ANY",
+ /* 280 */ "vtabargtoken ::= lp anylist RP",
+ /* 281 */ "lp ::= LP",
+ /* 282 */ "with ::= WITH wqlist",
+ /* 283 */ "with ::= WITH RECURSIVE wqlist",
+ /* 284 */ "wqlist ::= nm eidlist_opt AS LP select RP",
+ /* 285 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP",
+ /* 286 */ "windowdefn_list ::= windowdefn",
+ /* 287 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn",
+ /* 288 */ "windowdefn ::= nm AS window",
+ /* 289 */ "window ::= LP part_opt orderby_opt frame_opt RP",
+ /* 290 */ "part_opt ::= PARTITION BY nexprlist",
+ /* 291 */ "part_opt ::=",
+ /* 292 */ "frame_opt ::=",
+ /* 293 */ "frame_opt ::= range_or_rows frame_bound_s",
+ /* 294 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e",
+ /* 295 */ "range_or_rows ::= RANGE",
+ /* 296 */ "range_or_rows ::= ROWS",
+ /* 297 */ "frame_bound_s ::= frame_bound",
+ /* 298 */ "frame_bound_s ::= UNBOUNDED PRECEDING",
+ /* 299 */ "frame_bound_e ::= frame_bound",
+ /* 300 */ "frame_bound_e ::= UNBOUNDED FOLLOWING",
+ /* 301 */ "frame_bound ::= expr PRECEDING",
+ /* 302 */ "frame_bound ::= CURRENT ROW",
+ /* 303 */ "frame_bound ::= expr FOLLOWING",
+ /* 304 */ "window_clause ::= WINDOW windowdefn_list",
+ /* 305 */ "over_clause ::= filter_opt OVER window",
+ /* 306 */ "over_clause ::= filter_opt OVER nm",
+ /* 307 */ "filter_opt ::=",
+ /* 308 */ "filter_opt ::= FILTER LP WHERE expr RP",
+ /* 309 */ "input ::= cmdlist",
+ /* 310 */ "cmdlist ::= cmdlist ecmd",
+ /* 311 */ "cmdlist ::= ecmd",
+ /* 312 */ "ecmd ::= SEMI",
+ /* 313 */ "ecmd ::= cmdx SEMI",
+ /* 314 */ "ecmd ::= explain cmdx",
+ /* 315 */ "trans_opt ::=",
+ /* 316 */ "trans_opt ::= TRANSACTION",
+ /* 317 */ "trans_opt ::= TRANSACTION nm",
+ /* 318 */ "savepoint_opt ::= SAVEPOINT",
+ /* 319 */ "savepoint_opt ::=",
+ /* 320 */ "cmd ::= create_table create_table_args",
+ /* 321 */ "columnlist ::= columnlist COMMA columnname carglist",
+ /* 322 */ "columnlist ::= columnname carglist",
+ /* 323 */ "nm ::= ID|INDEXED",
+ /* 324 */ "nm ::= STRING",
+ /* 325 */ "nm ::= JOIN_KW",
+ /* 326 */ "typetoken ::= typename",
+ /* 327 */ "typename ::= ID|STRING",
+ /* 328 */ "signed ::= plus_num",
+ /* 329 */ "signed ::= minus_num",
+ /* 330 */ "carglist ::= carglist ccons",
+ /* 331 */ "carglist ::=",
+ /* 332 */ "ccons ::= NULL onconf",
+ /* 333 */ "conslist_opt ::= COMMA conslist",
+ /* 334 */ "conslist ::= conslist tconscomma tcons",
+ /* 335 */ "conslist ::= tcons",
+ /* 336 */ "tconscomma ::=",
+ /* 337 */ "defer_subclause_opt ::= defer_subclause",
+ /* 338 */ "resolvetype ::= raisetype",
+ /* 339 */ "selectnowith ::= oneselect",
+ /* 340 */ "oneselect ::= values",
+ /* 341 */ "sclp ::= selcollist COMMA",
+ /* 342 */ "as ::= ID|STRING",
+ /* 343 */ "expr ::= term",
+ /* 344 */ "likeop ::= LIKE_KW|MATCH",
+ /* 345 */ "exprlist ::= nexprlist",
+ /* 346 */ "nmnum ::= plus_num",
+ /* 347 */ "nmnum ::= nm",
+ /* 348 */ "nmnum ::= ON",
+ /* 349 */ "nmnum ::= DELETE",
+ /* 350 */ "nmnum ::= DEFAULT",
+ /* 351 */ "plus_num ::= INTEGER|FLOAT",
+ /* 352 */ "foreach_clause ::=",
+ /* 353 */ "foreach_clause ::= FOR EACH ROW",
+ /* 354 */ "trnm ::= nm",
+ /* 355 */ "tridxby ::=",
+ /* 356 */ "database_kw_opt ::= DATABASE",
+ /* 357 */ "database_kw_opt ::=",
+ /* 358 */ "kwcolumn_opt ::=",
+ /* 359 */ "kwcolumn_opt ::= COLUMNKW",
+ /* 360 */ "vtabarglist ::= vtabarg",
+ /* 361 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
+ /* 362 */ "vtabarg ::= vtabarg vtabargtoken",
+ /* 363 */ "anylist ::=",
+ /* 364 */ "anylist ::= anylist LP anylist RP",
+ /* 365 */ "anylist ::= anylist ANY",
+ /* 366 */ "with ::=",
 };
 #endif /* NDEBUG */
 
@@ -143135,73 +147781,96 @@ static void yy_destructor(
     ** inside the C code.
     */
 /********* Begin destructor definitions ***************************************/
-    case 164: /* select */
-    case 196: /* selectnowith */
-    case 197: /* oneselect */
-    case 208: /* values */
+    case 174: /* select */
+    case 206: /* selectnowith */
+    case 207: /* oneselect */
+    case 219: /* values */
+{
+sqlite3SelectDelete(pParse->db, (yypminor->yy489));
+}
+      break;
+    case 184: /* term */
+    case 185: /* expr */
+    case 213: /* where_opt */
+    case 215: /* having_opt */
+    case 227: /* on_opt */
+    case 242: /* case_operand */
+    case 244: /* case_else */
+    case 253: /* when_clause */
+    case 258: /* key_opt */
+    case 272: /* filter_opt */
 {
-sqlite3SelectDelete(pParse->db, (yypminor->yy399));
+sqlite3ExprDelete(pParse->db, (yypminor->yy18));
 }
       break;
-    case 174: /* term */
-    case 175: /* expr */
-    case 203: /* where_opt */
-    case 205: /* having_opt */
-    case 217: /* on_opt */
-    case 230: /* case_operand */
-    case 232: /* case_else */
-    case 241: /* when_clause */
-    case 246: /* key_opt */
+    case 189: /* eidlist_opt */
+    case 198: /* sortlist */
+    case 199: /* eidlist */
+    case 211: /* selcollist */
+    case 214: /* groupby_opt */
+    case 216: /* orderby_opt */
+    case 220: /* nexprlist */
+    case 221: /* sclp */
+    case 229: /* exprlist */
+    case 233: /* setlist */
+    case 241: /* paren_exprlist */
+    case 243: /* case_exprlist */
+    case 271: /* part_opt */
 {
-sqlite3ExprDelete(pParse->db, (yypminor->yy182));
+sqlite3ExprListDelete(pParse->db, (yypminor->yy420));
 }
       break;
-    case 179: /* eidlist_opt */
-    case 188: /* sortlist */
-    case 189: /* eidlist */
-    case 201: /* selcollist */
-    case 204: /* groupby_opt */
-    case 206: /* orderby_opt */
-    case 209: /* nexprlist */
-    case 210: /* exprlist */
-    case 211: /* sclp */
-    case 222: /* setlist */
-    case 229: /* paren_exprlist */
-    case 231: /* case_exprlist */
+    case 205: /* fullname */
+    case 212: /* from */
+    case 223: /* seltablist */
+    case 224: /* stl_prefix */
+    case 230: /* xfullname */
 {
-sqlite3ExprListDelete(pParse->db, (yypminor->yy232));
+sqlite3SrcListDelete(pParse->db, (yypminor->yy135));
 }
       break;
-    case 195: /* fullname */
-    case 202: /* from */
-    case 213: /* seltablist */
-    case 214: /* stl_prefix */
-    case 219: /* xfullname */
+    case 208: /* wqlist */
 {
-sqlite3SrcListDelete(pParse->db, (yypminor->yy427));
+sqlite3WithDelete(pParse->db, (yypminor->yy449));
 }
       break;
-    case 198: /* wqlist */
+    case 218: /* window_clause */
+    case 267: /* windowdefn_list */
 {
-sqlite3WithDelete(pParse->db, (yypminor->yy91));
+sqlite3WindowListDelete(pParse->db, (yypminor->yy327));
 }
       break;
-    case 218: /* using_opt */
-    case 220: /* idlist */
-    case 224: /* idlist_opt */
+    case 228: /* using_opt */
+    case 231: /* idlist */
+    case 235: /* idlist_opt */
 {
-sqlite3IdListDelete(pParse->db, (yypminor->yy510));
+sqlite3IdListDelete(pParse->db, (yypminor->yy48));
 }
       break;
-    case 237: /* trigger_cmd_list */
-    case 242: /* trigger_cmd */
+    case 237: /* over_clause */
+    case 268: /* windowdefn */
+    case 269: /* window */
+    case 270: /* frame_opt */
 {
-sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy47));
+sqlite3WindowDelete(pParse->db, (yypminor->yy327));
 }
       break;
-    case 239: /* trigger_event */
+    case 249: /* trigger_cmd_list */
+    case 254: /* trigger_cmd */
 {
-sqlite3IdListDelete(pParse->db, (yypminor->yy300).b);
+sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy207));
+}
+      break;
+    case 251: /* trigger_event */
+{
+sqlite3IdListDelete(pParse->db, (yypminor->yy34).b);
+}
+      break;
+    case 274: /* frame_bound */
+    case 275: /* frame_bound_s */
+    case 276: /* frame_bound_e */
+{
+sqlite3ExprDelete(pParse->db, (yypminor->yy119).pExpr);
 }
       break;
 /********* End destructor definitions *****************************************/
@@ -143327,11 +147996,11 @@ static YYACTIONTYPE yy_find_shift_action(
   do{
     i = yy_shift_ofst[stateno];
     assert( i>=0 );
-    assert( i+YYNTOKEN<=(int)sizeof(yy_lookahead)/sizeof(yy_lookahead[0]) );
+    /* assert( i+YYNTOKEN<=(int)YY_NLOOKAHEAD ); */
     assert( iLookAhead!=YYNOCODE );
     assert( iLookAhead < YYNTOKEN );
     i += iLookAhead;
-    if( yy_lookahead[i]!=iLookAhead ){
+    if( i>=YY_NLOOKAHEAD || yy_lookahead[i]!=iLookAhead ){
 #ifdef YYFALLBACK
       YYCODETYPE iFallback;            /* Fallback token */
       if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
@@ -143357,6 +148026,7 @@ static YYACTIONTYPE yy_find_shift_action(
 #if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT
           j<YY_ACTTAB_COUNT &&
 #endif
+          j<(int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])) &&
           yy_lookahead[j]==YYWILDCARD && iLookAhead>0
         ){
 #ifndef NDEBUG
@@ -143381,7 +148051,7 @@ static YYACTIONTYPE yy_find_shift_action(
 ** Find the appropriate action for a parser given the non-terminal
 ** look-ahead token iLookAhead.
 */
-static int yy_find_reduce_action(
+static YYACTIONTYPE yy_find_reduce_action(
   YYACTIONTYPE stateno,     /* Current state number */
   YYCODETYPE iLookAhead     /* The look-ahead token */
 ){
@@ -143499,347 +148169,373 @@ static const struct {
   YYCODETYPE lhs;       /* Symbol on the left-hand side of the rule */
   signed char nrhs;     /* Negative of the number of RHS symbols in the rule */
 } yyRuleInfo[] = {
-  {  149,   -1 }, /* (0) explain ::= EXPLAIN */
-  {  149,   -3 }, /* (1) explain ::= EXPLAIN QUERY PLAN */
-  {  148,   -1 }, /* (2) cmdx ::= cmd */
-  {  150,   -3 }, /* (3) cmd ::= BEGIN transtype trans_opt */
-  {  151,    0 }, /* (4) transtype ::= */
-  {  151,   -1 }, /* (5) transtype ::= DEFERRED */
-  {  151,   -1 }, /* (6) transtype ::= IMMEDIATE */
-  {  151,   -1 }, /* (7) transtype ::= EXCLUSIVE */
-  {  150,   -2 }, /* (8) cmd ::= COMMIT|END trans_opt */
-  {  150,   -2 }, /* (9) cmd ::= ROLLBACK trans_opt */
-  {  150,   -2 }, /* (10) cmd ::= SAVEPOINT nm */
-  {  150,   -3 }, /* (11) cmd ::= RELEASE savepoint_opt nm */
-  {  150,   -5 }, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
-  {  155,   -6 }, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */
-  {  157,   -1 }, /* (14) createkw ::= CREATE */
-  {  159,    0 }, /* (15) ifnotexists ::= */
-  {  159,   -3 }, /* (16) ifnotexists ::= IF NOT EXISTS */
-  {  158,   -1 }, /* (17) temp ::= TEMP */
-  {  158,    0 }, /* (18) temp ::= */
-  {  156,   -5 }, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_options */
-  {  156,   -2 }, /* (20) create_table_args ::= AS select */
-  {  163,    0 }, /* (21) table_options ::= */
-  {  163,   -2 }, /* (22) table_options ::= WITHOUT nm */
-  {  165,   -2 }, /* (23) columnname ::= nm typetoken */
-  {  167,    0 }, /* (24) typetoken ::= */
-  {  167,   -4 }, /* (25) typetoken ::= typename LP signed RP */
-  {  167,   -6 }, /* (26) typetoken ::= typename LP signed COMMA signed RP */
-  {  168,   -2 }, /* (27) typename ::= typename ID|STRING */
-  {  172,    0 }, /* (28) scanpt ::= */
-  {  173,   -2 }, /* (29) ccons ::= CONSTRAINT nm */
-  {  173,   -4 }, /* (30) ccons ::= DEFAULT scanpt term scanpt */
-  {  173,   -4 }, /* (31) ccons ::= DEFAULT LP expr RP */
-  {  173,   -4 }, /* (32) ccons ::= DEFAULT PLUS term scanpt */
-  {  173,   -4 }, /* (33) ccons ::= DEFAULT MINUS term scanpt */
-  {  173,   -3 }, /* (34) ccons ::= DEFAULT scanpt ID|INDEXED */
-  {  173,   -3 }, /* (35) ccons ::= NOT NULL onconf */
-  {  173,   -5 }, /* (36) ccons ::= PRIMARY KEY sortorder onconf autoinc */
-  {  173,   -2 }, /* (37) ccons ::= UNIQUE onconf */
-  {  173,   -4 }, /* (38) ccons ::= CHECK LP expr RP */
-  {  173,   -4 }, /* (39) ccons ::= REFERENCES nm eidlist_opt refargs */
-  {  173,   -1 }, /* (40) ccons ::= defer_subclause */
-  {  173,   -2 }, /* (41) ccons ::= COLLATE ID|STRING */
-  {  178,    0 }, /* (42) autoinc ::= */
-  {  178,   -1 }, /* (43) autoinc ::= AUTOINCR */
-  {  180,    0 }, /* (44) refargs ::= */
-  {  180,   -2 }, /* (45) refargs ::= refargs refarg */
-  {  182,   -2 }, /* (46) refarg ::= MATCH nm */
-  {  182,   -3 }, /* (47) refarg ::= ON INSERT refact */
-  {  182,   -3 }, /* (48) refarg ::= ON DELETE refact */
-  {  182,   -3 }, /* (49) refarg ::= ON UPDATE refact */
-  {  183,   -2 }, /* (50) refact ::= SET NULL */
-  {  183,   -2 }, /* (51) refact ::= SET DEFAULT */
-  {  183,   -1 }, /* (52) refact ::= CASCADE */
-  {  183,   -1 }, /* (53) refact ::= RESTRICT */
-  {  183,   -2 }, /* (54) refact ::= NO ACTION */
-  {  181,   -3 }, /* (55) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
-  {  181,   -2 }, /* (56) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
-  {  184,    0 }, /* (57) init_deferred_pred_opt ::= */
-  {  184,   -2 }, /* (58) init_deferred_pred_opt ::= INITIALLY DEFERRED */
-  {  184,   -2 }, /* (59) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
-  {  162,    0 }, /* (60) conslist_opt ::= */
-  {  186,   -1 }, /* (61) tconscomma ::= COMMA */
-  {  187,   -2 }, /* (62) tcons ::= CONSTRAINT nm */
-  {  187,   -7 }, /* (63) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
-  {  187,   -5 }, /* (64) tcons ::= UNIQUE LP sortlist RP onconf */
-  {  187,   -5 }, /* (65) tcons ::= CHECK LP expr RP onconf */
-  {  187,  -10 }, /* (66) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
-  {  190,    0 }, /* (67) defer_subclause_opt ::= */
-  {  176,    0 }, /* (68) onconf ::= */
-  {  176,   -3 }, /* (69) onconf ::= ON CONFLICT resolvetype */
-  {  191,    0 }, /* (70) orconf ::= */
-  {  191,   -2 }, /* (71) orconf ::= OR resolvetype */
-  {  192,   -1 }, /* (72) resolvetype ::= IGNORE */
-  {  192,   -1 }, /* (73) resolvetype ::= REPLACE */
-  {  150,   -4 }, /* (74) cmd ::= DROP TABLE ifexists fullname */
-  {  194,   -2 }, /* (75) ifexists ::= IF EXISTS */
-  {  194,    0 }, /* (76) ifexists ::= */
-  {  150,   -9 }, /* (77) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
-  {  150,   -4 }, /* (78) cmd ::= DROP VIEW ifexists fullname */
-  {  150,   -1 }, /* (79) cmd ::= select */
-  {  164,   -3 }, /* (80) select ::= WITH wqlist selectnowith */
-  {  164,   -4 }, /* (81) select ::= WITH RECURSIVE wqlist selectnowith */
-  {  164,   -1 }, /* (82) select ::= selectnowith */
-  {  196,   -3 }, /* (83) selectnowith ::= selectnowith multiselect_op oneselect */
-  {  199,   -1 }, /* (84) multiselect_op ::= UNION */
-  {  199,   -2 }, /* (85) multiselect_op ::= UNION ALL */
-  {  199,   -1 }, /* (86) multiselect_op ::= EXCEPT|INTERSECT */
-  {  197,   -9 }, /* (87) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
-  {  208,   -4 }, /* (88) values ::= VALUES LP nexprlist RP */
-  {  208,   -5 }, /* (89) values ::= values COMMA LP exprlist RP */
-  {  200,   -1 }, /* (90) distinct ::= DISTINCT */
-  {  200,   -1 }, /* (91) distinct ::= ALL */
-  {  200,    0 }, /* (92) distinct ::= */
-  {  211,    0 }, /* (93) sclp ::= */
-  {  201,   -5 }, /* (94) selcollist ::= sclp scanpt expr scanpt as */
-  {  201,   -3 }, /* (95) selcollist ::= sclp scanpt STAR */
-  {  201,   -5 }, /* (96) selcollist ::= sclp scanpt nm DOT STAR */
-  {  212,   -2 }, /* (97) as ::= AS nm */
-  {  212,    0 }, /* (98) as ::= */
-  {  202,    0 }, /* (99) from ::= */
-  {  202,   -2 }, /* (100) from ::= FROM seltablist */
-  {  214,   -2 }, /* (101) stl_prefix ::= seltablist joinop */
-  {  214,    0 }, /* (102) stl_prefix ::= */
-  {  213,   -7 }, /* (103) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
-  {  213,   -9 }, /* (104) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
-  {  213,   -7 }, /* (105) seltablist ::= stl_prefix LP select RP as on_opt using_opt */
-  {  213,   -7 }, /* (106) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
-  {  160,    0 }, /* (107) dbnm ::= */
-  {  160,   -2 }, /* (108) dbnm ::= DOT nm */
-  {  195,   -1 }, /* (109) fullname ::= nm */
-  {  195,   -3 }, /* (110) fullname ::= nm DOT nm */
-  {  219,   -1 }, /* (111) xfullname ::= nm */
-  {  219,   -3 }, /* (112) xfullname ::= nm DOT nm */
-  {  219,   -5 }, /* (113) xfullname ::= nm DOT nm AS nm */
-  {  219,   -3 }, /* (114) xfullname ::= nm AS nm */
-  {  215,   -1 }, /* (115) joinop ::= COMMA|JOIN */
-  {  215,   -2 }, /* (116) joinop ::= JOIN_KW JOIN */
-  {  215,   -3 }, /* (117) joinop ::= JOIN_KW nm JOIN */
-  {  215,   -4 }, /* (118) joinop ::= JOIN_KW nm nm JOIN */
-  {  217,   -2 }, /* (119) on_opt ::= ON expr */
-  {  217,    0 }, /* (120) on_opt ::= */
-  {  216,    0 }, /* (121) indexed_opt ::= */
-  {  216,   -3 }, /* (122) indexed_opt ::= INDEXED BY nm */
-  {  216,   -2 }, /* (123) indexed_opt ::= NOT INDEXED */
-  {  218,   -4 }, /* (124) using_opt ::= USING LP idlist RP */
-  {  218,    0 }, /* (125) using_opt ::= */
-  {  206,    0 }, /* (126) orderby_opt ::= */
-  {  206,   -3 }, /* (127) orderby_opt ::= ORDER BY sortlist */
-  {  188,   -4 }, /* (128) sortlist ::= sortlist COMMA expr sortorder */
-  {  188,   -2 }, /* (129) sortlist ::= expr sortorder */
-  {  177,   -1 }, /* (130) sortorder ::= ASC */
-  {  177,   -1 }, /* (131) sortorder ::= DESC */
-  {  177,    0 }, /* (132) sortorder ::= */
-  {  204,    0 }, /* (133) groupby_opt ::= */
-  {  204,   -3 }, /* (134) groupby_opt ::= GROUP BY nexprlist */
-  {  205,    0 }, /* (135) having_opt ::= */
-  {  205,   -2 }, /* (136) having_opt ::= HAVING expr */
-  {  207,    0 }, /* (137) limit_opt ::= */
-  {  207,   -2 }, /* (138) limit_opt ::= LIMIT expr */
-  {  207,   -4 }, /* (139) limit_opt ::= LIMIT expr OFFSET expr */
-  {  207,   -4 }, /* (140) limit_opt ::= LIMIT expr COMMA expr */
-  {  150,   -6 }, /* (141) cmd ::= with DELETE FROM xfullname indexed_opt where_opt */
-  {  203,    0 }, /* (142) where_opt ::= */
-  {  203,   -2 }, /* (143) where_opt ::= WHERE expr */
-  {  150,   -8 }, /* (144) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */
-  {  222,   -5 }, /* (145) setlist ::= setlist COMMA nm EQ expr */
-  {  222,   -7 }, /* (146) setlist ::= setlist COMMA LP idlist RP EQ expr */
-  {  222,   -3 }, /* (147) setlist ::= nm EQ expr */
-  {  222,   -5 }, /* (148) setlist ::= LP idlist RP EQ expr */
-  {  150,   -7 }, /* (149) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
-  {  150,   -7 }, /* (150) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */
-  {  225,    0 }, /* (151) upsert ::= */
-  {  225,  -11 }, /* (152) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */
-  {  225,   -8 }, /* (153) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */
-  {  225,   -4 }, /* (154) upsert ::= ON CONFLICT DO NOTHING */
-  {  223,   -2 }, /* (155) insert_cmd ::= INSERT orconf */
-  {  223,   -1 }, /* (156) insert_cmd ::= REPLACE */
-  {  224,    0 }, /* (157) idlist_opt ::= */
-  {  224,   -3 }, /* (158) idlist_opt ::= LP idlist RP */
-  {  220,   -3 }, /* (159) idlist ::= idlist COMMA nm */
-  {  220,   -1 }, /* (160) idlist ::= nm */
-  {  175,   -3 }, /* (161) expr ::= LP expr RP */
-  {  175,   -1 }, /* (162) expr ::= ID|INDEXED */
-  {  175,   -1 }, /* (163) expr ::= JOIN_KW */
-  {  175,   -3 }, /* (164) expr ::= nm DOT nm */
-  {  175,   -5 }, /* (165) expr ::= nm DOT nm DOT nm */
-  {  174,   -1 }, /* (166) term ::= NULL|FLOAT|BLOB */
-  {  174,   -1 }, /* (167) term ::= STRING */
-  {  174,   -1 }, /* (168) term ::= INTEGER */
-  {  175,   -1 }, /* (169) expr ::= VARIABLE */
-  {  175,   -3 }, /* (170) expr ::= expr COLLATE ID|STRING */
-  {  175,   -6 }, /* (171) expr ::= CAST LP expr AS typetoken RP */
-  {  175,   -5 }, /* (172) expr ::= ID|INDEXED LP distinct exprlist RP */
-  {  175,   -4 }, /* (173) expr ::= ID|INDEXED LP STAR RP */
-  {  174,   -1 }, /* (174) term ::= CTIME_KW */
-  {  175,   -5 }, /* (175) expr ::= LP nexprlist COMMA expr RP */
-  {  175,   -3 }, /* (176) expr ::= expr AND expr */
-  {  175,   -3 }, /* (177) expr ::= expr OR expr */
-  {  175,   -3 }, /* (178) expr ::= expr LT|GT|GE|LE expr */
-  {  175,   -3 }, /* (179) expr ::= expr EQ|NE expr */
-  {  175,   -3 }, /* (180) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
-  {  175,   -3 }, /* (181) expr ::= expr PLUS|MINUS expr */
-  {  175,   -3 }, /* (182) expr ::= expr STAR|SLASH|REM expr */
-  {  175,   -3 }, /* (183) expr ::= expr CONCAT expr */
-  {  226,   -2 }, /* (184) likeop ::= NOT LIKE_KW|MATCH */
-  {  175,   -3 }, /* (185) expr ::= expr likeop expr */
-  {  175,   -5 }, /* (186) expr ::= expr likeop expr ESCAPE expr */
-  {  175,   -2 }, /* (187) expr ::= expr ISNULL|NOTNULL */
-  {  175,   -3 }, /* (188) expr ::= expr NOT NULL */
-  {  175,   -3 }, /* (189) expr ::= expr IS expr */
-  {  175,   -4 }, /* (190) expr ::= expr IS NOT expr */
-  {  175,   -2 }, /* (191) expr ::= NOT expr */
-  {  175,   -2 }, /* (192) expr ::= BITNOT expr */
-  {  175,   -2 }, /* (193) expr ::= MINUS expr */
-  {  175,   -2 }, /* (194) expr ::= PLUS expr */
-  {  227,   -1 }, /* (195) between_op ::= BETWEEN */
-  {  227,   -2 }, /* (196) between_op ::= NOT BETWEEN */
-  {  175,   -5 }, /* (197) expr ::= expr between_op expr AND expr */
-  {  228,   -1 }, /* (198) in_op ::= IN */
-  {  228,   -2 }, /* (199) in_op ::= NOT IN */
-  {  175,   -5 }, /* (200) expr ::= expr in_op LP exprlist RP */
-  {  175,   -3 }, /* (201) expr ::= LP select RP */
-  {  175,   -5 }, /* (202) expr ::= expr in_op LP select RP */
-  {  175,   -5 }, /* (203) expr ::= expr in_op nm dbnm paren_exprlist */
-  {  175,   -4 }, /* (204) expr ::= EXISTS LP select RP */
-  {  175,   -5 }, /* (205) expr ::= CASE case_operand case_exprlist case_else END */
-  {  231,   -5 }, /* (206) case_exprlist ::= case_exprlist WHEN expr THEN expr */
-  {  231,   -4 }, /* (207) case_exprlist ::= WHEN expr THEN expr */
-  {  232,   -2 }, /* (208) case_else ::= ELSE expr */
-  {  232,    0 }, /* (209) case_else ::= */
-  {  230,   -1 }, /* (210) case_operand ::= expr */
-  {  230,    0 }, /* (211) case_operand ::= */
-  {  210,    0 }, /* (212) exprlist ::= */
-  {  209,   -3 }, /* (213) nexprlist ::= nexprlist COMMA expr */
-  {  209,   -1 }, /* (214) nexprlist ::= expr */
-  {  229,    0 }, /* (215) paren_exprlist ::= */
-  {  229,   -3 }, /* (216) paren_exprlist ::= LP exprlist RP */
-  {  150,  -12 }, /* (217) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
-  {  233,   -1 }, /* (218) uniqueflag ::= UNIQUE */
-  {  233,    0 }, /* (219) uniqueflag ::= */
-  {  179,    0 }, /* (220) eidlist_opt ::= */
-  {  179,   -3 }, /* (221) eidlist_opt ::= LP eidlist RP */
-  {  189,   -5 }, /* (222) eidlist ::= eidlist COMMA nm collate sortorder */
-  {  189,   -3 }, /* (223) eidlist ::= nm collate sortorder */
-  {  234,    0 }, /* (224) collate ::= */
-  {  234,   -2 }, /* (225) collate ::= COLLATE ID|STRING */
-  {  150,   -4 }, /* (226) cmd ::= DROP INDEX ifexists fullname */
-  {  150,   -1 }, /* (227) cmd ::= VACUUM */
-  {  150,   -2 }, /* (228) cmd ::= VACUUM nm */
-  {  150,   -3 }, /* (229) cmd ::= PRAGMA nm dbnm */
-  {  150,   -5 }, /* (230) cmd ::= PRAGMA nm dbnm EQ nmnum */
-  {  150,   -6 }, /* (231) cmd ::= PRAGMA nm dbnm LP nmnum RP */
-  {  150,   -5 }, /* (232) cmd ::= PRAGMA nm dbnm EQ minus_num */
-  {  150,   -6 }, /* (233) cmd ::= PRAGMA nm dbnm LP minus_num RP */
-  {  170,   -2 }, /* (234) plus_num ::= PLUS INTEGER|FLOAT */
-  {  171,   -2 }, /* (235) minus_num ::= MINUS INTEGER|FLOAT */
-  {  150,   -5 }, /* (236) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
-  {  236,  -11 }, /* (237) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
-  {  238,   -1 }, /* (238) trigger_time ::= BEFORE|AFTER */
-  {  238,   -2 }, /* (239) trigger_time ::= INSTEAD OF */
-  {  238,    0 }, /* (240) trigger_time ::= */
-  {  239,   -1 }, /* (241) trigger_event ::= DELETE|INSERT */
-  {  239,   -1 }, /* (242) trigger_event ::= UPDATE */
-  {  239,   -3 }, /* (243) trigger_event ::= UPDATE OF idlist */
-  {  241,    0 }, /* (244) when_clause ::= */
-  {  241,   -2 }, /* (245) when_clause ::= WHEN expr */
-  {  237,   -3 }, /* (246) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
-  {  237,   -2 }, /* (247) trigger_cmd_list ::= trigger_cmd SEMI */
-  {  243,   -3 }, /* (248) trnm ::= nm DOT nm */
-  {  244,   -3 }, /* (249) tridxby ::= INDEXED BY nm */
-  {  244,   -2 }, /* (250) tridxby ::= NOT INDEXED */
-  {  242,   -8 }, /* (251) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */
-  {  242,   -8 }, /* (252) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
-  {  242,   -6 }, /* (253) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
-  {  242,   -3 }, /* (254) trigger_cmd ::= scanpt select scanpt */
-  {  175,   -4 }, /* (255) expr ::= RAISE LP IGNORE RP */
-  {  175,   -6 }, /* (256) expr ::= RAISE LP raisetype COMMA nm RP */
-  {  193,   -1 }, /* (257) raisetype ::= ROLLBACK */
-  {  193,   -1 }, /* (258) raisetype ::= ABORT */
-  {  193,   -1 }, /* (259) raisetype ::= FAIL */
-  {  150,   -4 }, /* (260) cmd ::= DROP TRIGGER ifexists fullname */
-  {  150,   -6 }, /* (261) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
-  {  150,   -3 }, /* (262) cmd ::= DETACH database_kw_opt expr */
-  {  246,    0 }, /* (263) key_opt ::= */
-  {  246,   -2 }, /* (264) key_opt ::= KEY expr */
-  {  150,   -1 }, /* (265) cmd ::= REINDEX */
-  {  150,   -3 }, /* (266) cmd ::= REINDEX nm dbnm */
-  {  150,   -1 }, /* (267) cmd ::= ANALYZE */
-  {  150,   -3 }, /* (268) cmd ::= ANALYZE nm dbnm */
-  {  150,   -6 }, /* (269) cmd ::= ALTER TABLE fullname RENAME TO nm */
-  {  150,   -7 }, /* (270) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
-  {  247,   -1 }, /* (271) add_column_fullname ::= fullname */
-  {  150,   -1 }, /* (272) cmd ::= create_vtab */
-  {  150,   -4 }, /* (273) cmd ::= create_vtab LP vtabarglist RP */
-  {  249,   -8 }, /* (274) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
-  {  251,    0 }, /* (275) vtabarg ::= */
-  {  252,   -1 }, /* (276) vtabargtoken ::= ANY */
-  {  252,   -3 }, /* (277) vtabargtoken ::= lp anylist RP */
-  {  253,   -1 }, /* (278) lp ::= LP */
-  {  221,   -2 }, /* (279) with ::= WITH wqlist */
-  {  221,   -3 }, /* (280) with ::= WITH RECURSIVE wqlist */
-  {  198,   -6 }, /* (281) wqlist ::= nm eidlist_opt AS LP select RP */
-  {  198,   -8 }, /* (282) wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
-  {  145,   -1 }, /* (283) input ::= cmdlist */
-  {  146,   -2 }, /* (284) cmdlist ::= cmdlist ecmd */
-  {  146,   -1 }, /* (285) cmdlist ::= ecmd */
-  {  147,   -1 }, /* (286) ecmd ::= SEMI */
-  {  147,   -2 }, /* (287) ecmd ::= cmdx SEMI */
-  {  147,   -2 }, /* (288) ecmd ::= explain cmdx */
-  {  152,    0 }, /* (289) trans_opt ::= */
-  {  152,   -1 }, /* (290) trans_opt ::= TRANSACTION */
-  {  152,   -2 }, /* (291) trans_opt ::= TRANSACTION nm */
-  {  154,   -1 }, /* (292) savepoint_opt ::= SAVEPOINT */
-  {  154,    0 }, /* (293) savepoint_opt ::= */
-  {  150,   -2 }, /* (294) cmd ::= create_table create_table_args */
-  {  161,   -4 }, /* (295) columnlist ::= columnlist COMMA columnname carglist */
-  {  161,   -2 }, /* (296) columnlist ::= columnname carglist */
-  {  153,   -1 }, /* (297) nm ::= ID|INDEXED */
-  {  153,   -1 }, /* (298) nm ::= STRING */
-  {  153,   -1 }, /* (299) nm ::= JOIN_KW */
-  {  167,   -1 }, /* (300) typetoken ::= typename */
-  {  168,   -1 }, /* (301) typename ::= ID|STRING */
-  {  169,   -1 }, /* (302) signed ::= plus_num */
-  {  169,   -1 }, /* (303) signed ::= minus_num */
-  {  166,   -2 }, /* (304) carglist ::= carglist ccons */
-  {  166,    0 }, /* (305) carglist ::= */
-  {  173,   -2 }, /* (306) ccons ::= NULL onconf */
-  {  162,   -2 }, /* (307) conslist_opt ::= COMMA conslist */
-  {  185,   -3 }, /* (308) conslist ::= conslist tconscomma tcons */
-  {  185,   -1 }, /* (309) conslist ::= tcons */
-  {  186,    0 }, /* (310) tconscomma ::= */
-  {  190,   -1 }, /* (311) defer_subclause_opt ::= defer_subclause */
-  {  192,   -1 }, /* (312) resolvetype ::= raisetype */
-  {  196,   -1 }, /* (313) selectnowith ::= oneselect */
-  {  197,   -1 }, /* (314) oneselect ::= values */
-  {  211,   -2 }, /* (315) sclp ::= selcollist COMMA */
-  {  212,   -1 }, /* (316) as ::= ID|STRING */
-  {  175,   -1 }, /* (317) expr ::= term */
-  {  226,   -1 }, /* (318) likeop ::= LIKE_KW|MATCH */
-  {  210,   -1 }, /* (319) exprlist ::= nexprlist */
-  {  235,   -1 }, /* (320) nmnum ::= plus_num */
-  {  235,   -1 }, /* (321) nmnum ::= nm */
-  {  235,   -1 }, /* (322) nmnum ::= ON */
-  {  235,   -1 }, /* (323) nmnum ::= DELETE */
-  {  235,   -1 }, /* (324) nmnum ::= DEFAULT */
-  {  170,   -1 }, /* (325) plus_num ::= INTEGER|FLOAT */
-  {  240,    0 }, /* (326) foreach_clause ::= */
-  {  240,   -3 }, /* (327) foreach_clause ::= FOR EACH ROW */
-  {  243,   -1 }, /* (328) trnm ::= nm */
-  {  244,    0 }, /* (329) tridxby ::= */
-  {  245,   -1 }, /* (330) database_kw_opt ::= DATABASE */
-  {  245,    0 }, /* (331) database_kw_opt ::= */
-  {  248,    0 }, /* (332) kwcolumn_opt ::= */
-  {  248,   -1 }, /* (333) kwcolumn_opt ::= COLUMNKW */
-  {  250,   -1 }, /* (334) vtabarglist ::= vtabarg */
-  {  250,   -3 }, /* (335) vtabarglist ::= vtabarglist COMMA vtabarg */
-  {  251,   -2 }, /* (336) vtabarg ::= vtabarg vtabargtoken */
-  {  254,    0 }, /* (337) anylist ::= */
-  {  254,   -4 }, /* (338) anylist ::= anylist LP anylist RP */
-  {  254,   -2 }, /* (339) anylist ::= anylist ANY */
-  {  221,    0 }, /* (340) with ::= */
+  {  159,   -1 }, /* (0) explain ::= EXPLAIN */
+  {  159,   -3 }, /* (1) explain ::= EXPLAIN QUERY PLAN */
+  {  158,   -1 }, /* (2) cmdx ::= cmd */
+  {  160,   -3 }, /* (3) cmd ::= BEGIN transtype trans_opt */
+  {  161,    0 }, /* (4) transtype ::= */
+  {  161,   -1 }, /* (5) transtype ::= DEFERRED */
+  {  161,   -1 }, /* (6) transtype ::= IMMEDIATE */
+  {  161,   -1 }, /* (7) transtype ::= EXCLUSIVE */
+  {  160,   -2 }, /* (8) cmd ::= COMMIT|END trans_opt */
+  {  160,   -2 }, /* (9) cmd ::= ROLLBACK trans_opt */
+  {  160,   -2 }, /* (10) cmd ::= SAVEPOINT nm */
+  {  160,   -3 }, /* (11) cmd ::= RELEASE savepoint_opt nm */
+  {  160,   -5 }, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
+  {  165,   -6 }, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */
+  {  167,   -1 }, /* (14) createkw ::= CREATE */
+  {  169,    0 }, /* (15) ifnotexists ::= */
+  {  169,   -3 }, /* (16) ifnotexists ::= IF NOT EXISTS */
+  {  168,   -1 }, /* (17) temp ::= TEMP */
+  {  168,    0 }, /* (18) temp ::= */
+  {  166,   -5 }, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_options */
+  {  166,   -2 }, /* (20) create_table_args ::= AS select */
+  {  173,    0 }, /* (21) table_options ::= */
+  {  173,   -2 }, /* (22) table_options ::= WITHOUT nm */
+  {  175,   -2 }, /* (23) columnname ::= nm typetoken */
+  {  177,    0 }, /* (24) typetoken ::= */
+  {  177,   -4 }, /* (25) typetoken ::= typename LP signed RP */
+  {  177,   -6 }, /* (26) typetoken ::= typename LP signed COMMA signed RP */
+  {  178,   -2 }, /* (27) typename ::= typename ID|STRING */
+  {  182,    0 }, /* (28) scanpt ::= */
+  {  183,   -2 }, /* (29) ccons ::= CONSTRAINT nm */
+  {  183,   -4 }, /* (30) ccons ::= DEFAULT scanpt term scanpt */
+  {  183,   -4 }, /* (31) ccons ::= DEFAULT LP expr RP */
+  {  183,   -4 }, /* (32) ccons ::= DEFAULT PLUS term scanpt */
+  {  183,   -4 }, /* (33) ccons ::= DEFAULT MINUS term scanpt */
+  {  183,   -3 }, /* (34) ccons ::= DEFAULT scanpt ID|INDEXED */
+  {  183,   -3 }, /* (35) ccons ::= NOT NULL onconf */
+  {  183,   -5 }, /* (36) ccons ::= PRIMARY KEY sortorder onconf autoinc */
+  {  183,   -2 }, /* (37) ccons ::= UNIQUE onconf */
+  {  183,   -4 }, /* (38) ccons ::= CHECK LP expr RP */
+  {  183,   -4 }, /* (39) ccons ::= REFERENCES nm eidlist_opt refargs */
+  {  183,   -1 }, /* (40) ccons ::= defer_subclause */
+  {  183,   -2 }, /* (41) ccons ::= COLLATE ID|STRING */
+  {  188,    0 }, /* (42) autoinc ::= */
+  {  188,   -1 }, /* (43) autoinc ::= AUTOINCR */
+  {  190,    0 }, /* (44) refargs ::= */
+  {  190,   -2 }, /* (45) refargs ::= refargs refarg */
+  {  192,   -2 }, /* (46) refarg ::= MATCH nm */
+  {  192,   -3 }, /* (47) refarg ::= ON INSERT refact */
+  {  192,   -3 }, /* (48) refarg ::= ON DELETE refact */
+  {  192,   -3 }, /* (49) refarg ::= ON UPDATE refact */
+  {  193,   -2 }, /* (50) refact ::= SET NULL */
+  {  193,   -2 }, /* (51) refact ::= SET DEFAULT */
+  {  193,   -1 }, /* (52) refact ::= CASCADE */
+  {  193,   -1 }, /* (53) refact ::= RESTRICT */
+  {  193,   -2 }, /* (54) refact ::= NO ACTION */
+  {  191,   -3 }, /* (55) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
+  {  191,   -2 }, /* (56) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
+  {  194,    0 }, /* (57) init_deferred_pred_opt ::= */
+  {  194,   -2 }, /* (58) init_deferred_pred_opt ::= INITIALLY DEFERRED */
+  {  194,   -2 }, /* (59) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
+  {  172,    0 }, /* (60) conslist_opt ::= */
+  {  196,   -1 }, /* (61) tconscomma ::= COMMA */
+  {  197,   -2 }, /* (62) tcons ::= CONSTRAINT nm */
+  {  197,   -7 }, /* (63) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
+  {  197,   -5 }, /* (64) tcons ::= UNIQUE LP sortlist RP onconf */
+  {  197,   -5 }, /* (65) tcons ::= CHECK LP expr RP onconf */
+  {  197,  -10 }, /* (66) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
+  {  200,    0 }, /* (67) defer_subclause_opt ::= */
+  {  186,    0 }, /* (68) onconf ::= */
+  {  186,   -3 }, /* (69) onconf ::= ON CONFLICT resolvetype */
+  {  201,    0 }, /* (70) orconf ::= */
+  {  201,   -2 }, /* (71) orconf ::= OR resolvetype */
+  {  202,   -1 }, /* (72) resolvetype ::= IGNORE */
+  {  202,   -1 }, /* (73) resolvetype ::= REPLACE */
+  {  160,   -4 }, /* (74) cmd ::= DROP TABLE ifexists fullname */
+  {  204,   -2 }, /* (75) ifexists ::= IF EXISTS */
+  {  204,    0 }, /* (76) ifexists ::= */
+  {  160,   -9 }, /* (77) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
+  {  160,   -4 }, /* (78) cmd ::= DROP VIEW ifexists fullname */
+  {  160,   -1 }, /* (79) cmd ::= select */
+  {  174,   -3 }, /* (80) select ::= WITH wqlist selectnowith */
+  {  174,   -4 }, /* (81) select ::= WITH RECURSIVE wqlist selectnowith */
+  {  174,   -1 }, /* (82) select ::= selectnowith */
+  {  206,   -3 }, /* (83) selectnowith ::= selectnowith multiselect_op oneselect */
+  {  209,   -1 }, /* (84) multiselect_op ::= UNION */
+  {  209,   -2 }, /* (85) multiselect_op ::= UNION ALL */
+  {  209,   -1 }, /* (86) multiselect_op ::= EXCEPT|INTERSECT */
+  {  207,   -9 }, /* (87) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
+  {  207,  -10 }, /* (88) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
+  {  219,   -4 }, /* (89) values ::= VALUES LP nexprlist RP */
+  {  219,   -5 }, /* (90) values ::= values COMMA LP nexprlist RP */
+  {  210,   -1 }, /* (91) distinct ::= DISTINCT */
+  {  210,   -1 }, /* (92) distinct ::= ALL */
+  {  210,    0 }, /* (93) distinct ::= */
+  {  221,    0 }, /* (94) sclp ::= */
+  {  211,   -5 }, /* (95) selcollist ::= sclp scanpt expr scanpt as */
+  {  211,   -3 }, /* (96) selcollist ::= sclp scanpt STAR */
+  {  211,   -5 }, /* (97) selcollist ::= sclp scanpt nm DOT STAR */
+  {  222,   -2 }, /* (98) as ::= AS nm */
+  {  222,    0 }, /* (99) as ::= */
+  {  212,    0 }, /* (100) from ::= */
+  {  212,   -2 }, /* (101) from ::= FROM seltablist */
+  {  224,   -2 }, /* (102) stl_prefix ::= seltablist joinop */
+  {  224,    0 }, /* (103) stl_prefix ::= */
+  {  223,   -7 }, /* (104) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
+  {  223,   -9 }, /* (105) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
+  {  223,   -7 }, /* (106) seltablist ::= stl_prefix LP select RP as on_opt using_opt */
+  {  223,   -7 }, /* (107) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
+  {  170,    0 }, /* (108) dbnm ::= */
+  {  170,   -2 }, /* (109) dbnm ::= DOT nm */
+  {  205,   -1 }, /* (110) fullname ::= nm */
+  {  205,   -3 }, /* (111) fullname ::= nm DOT nm */
+  {  230,   -1 }, /* (112) xfullname ::= nm */
+  {  230,   -3 }, /* (113) xfullname ::= nm DOT nm */
+  {  230,   -5 }, /* (114) xfullname ::= nm DOT nm AS nm */
+  {  230,   -3 }, /* (115) xfullname ::= nm AS nm */
+  {  225,   -1 }, /* (116) joinop ::= COMMA|JOIN */
+  {  225,   -2 }, /* (117) joinop ::= JOIN_KW JOIN */
+  {  225,   -3 }, /* (118) joinop ::= JOIN_KW nm JOIN */
+  {  225,   -4 }, /* (119) joinop ::= JOIN_KW nm nm JOIN */
+  {  227,   -2 }, /* (120) on_opt ::= ON expr */
+  {  227,    0 }, /* (121) on_opt ::= */
+  {  226,    0 }, /* (122) indexed_opt ::= */
+  {  226,   -3 }, /* (123) indexed_opt ::= INDEXED BY nm */
+  {  226,   -2 }, /* (124) indexed_opt ::= NOT INDEXED */
+  {  228,   -4 }, /* (125) using_opt ::= USING LP idlist RP */
+  {  228,    0 }, /* (126) using_opt ::= */
+  {  216,    0 }, /* (127) orderby_opt ::= */
+  {  216,   -3 }, /* (128) orderby_opt ::= ORDER BY sortlist */
+  {  198,   -4 }, /* (129) sortlist ::= sortlist COMMA expr sortorder */
+  {  198,   -2 }, /* (130) sortlist ::= expr sortorder */
+  {  187,   -1 }, /* (131) sortorder ::= ASC */
+  {  187,   -1 }, /* (132) sortorder ::= DESC */
+  {  187,    0 }, /* (133) sortorder ::= */
+  {  214,    0 }, /* (134) groupby_opt ::= */
+  {  214,   -3 }, /* (135) groupby_opt ::= GROUP BY nexprlist */
+  {  215,    0 }, /* (136) having_opt ::= */
+  {  215,   -2 }, /* (137) having_opt ::= HAVING expr */
+  {  217,    0 }, /* (138) limit_opt ::= */
+  {  217,   -2 }, /* (139) limit_opt ::= LIMIT expr */
+  {  217,   -4 }, /* (140) limit_opt ::= LIMIT expr OFFSET expr */
+  {  217,   -4 }, /* (141) limit_opt ::= LIMIT expr COMMA expr */
+  {  160,   -6 }, /* (142) cmd ::= with DELETE FROM xfullname indexed_opt where_opt */
+  {  213,    0 }, /* (143) where_opt ::= */
+  {  213,   -2 }, /* (144) where_opt ::= WHERE expr */
+  {  160,   -8 }, /* (145) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */
+  {  233,   -5 }, /* (146) setlist ::= setlist COMMA nm EQ expr */
+  {  233,   -7 }, /* (147) setlist ::= setlist COMMA LP idlist RP EQ expr */
+  {  233,   -3 }, /* (148) setlist ::= nm EQ expr */
+  {  233,   -5 }, /* (149) setlist ::= LP idlist RP EQ expr */
+  {  160,   -7 }, /* (150) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
+  {  160,   -7 }, /* (151) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */
+  {  236,    0 }, /* (152) upsert ::= */
+  {  236,  -11 }, /* (153) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */
+  {  236,   -8 }, /* (154) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */
+  {  236,   -4 }, /* (155) upsert ::= ON CONFLICT DO NOTHING */
+  {  234,   -2 }, /* (156) insert_cmd ::= INSERT orconf */
+  {  234,   -1 }, /* (157) insert_cmd ::= REPLACE */
+  {  235,    0 }, /* (158) idlist_opt ::= */
+  {  235,   -3 }, /* (159) idlist_opt ::= LP idlist RP */
+  {  231,   -3 }, /* (160) idlist ::= idlist COMMA nm */
+  {  231,   -1 }, /* (161) idlist ::= nm */
+  {  185,   -3 }, /* (162) expr ::= LP expr RP */
+  {  185,   -1 }, /* (163) expr ::= ID|INDEXED */
+  {  185,   -1 }, /* (164) expr ::= JOIN_KW */
+  {  185,   -3 }, /* (165) expr ::= nm DOT nm */
+  {  185,   -5 }, /* (166) expr ::= nm DOT nm DOT nm */
+  {  184,   -1 }, /* (167) term ::= NULL|FLOAT|BLOB */
+  {  184,   -1 }, /* (168) term ::= STRING */
+  {  184,   -1 }, /* (169) term ::= INTEGER */
+  {  185,   -1 }, /* (170) expr ::= VARIABLE */
+  {  185,   -3 }, /* (171) expr ::= expr COLLATE ID|STRING */
+  {  185,   -6 }, /* (172) expr ::= CAST LP expr AS typetoken RP */
+  {  185,   -5 }, /* (173) expr ::= ID|INDEXED LP distinct exprlist RP */
+  {  185,   -4 }, /* (174) expr ::= ID|INDEXED LP STAR RP */
+  {  185,   -6 }, /* (175) expr ::= ID|INDEXED LP distinct exprlist RP over_clause */
+  {  185,   -5 }, /* (176) expr ::= ID|INDEXED LP STAR RP over_clause */
+  {  184,   -1 }, /* (177) term ::= CTIME_KW */
+  {  185,   -5 }, /* (178) expr ::= LP nexprlist COMMA expr RP */
+  {  185,   -3 }, /* (179) expr ::= expr AND expr */
+  {  185,   -3 }, /* (180) expr ::= expr OR expr */
+  {  185,   -3 }, /* (181) expr ::= expr LT|GT|GE|LE expr */
+  {  185,   -3 }, /* (182) expr ::= expr EQ|NE expr */
+  {  185,   -3 }, /* (183) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
+  {  185,   -3 }, /* (184) expr ::= expr PLUS|MINUS expr */
+  {  185,   -3 }, /* (185) expr ::= expr STAR|SLASH|REM expr */
+  {  185,   -3 }, /* (186) expr ::= expr CONCAT expr */
+  {  238,   -2 }, /* (187) likeop ::= NOT LIKE_KW|MATCH */
+  {  185,   -3 }, /* (188) expr ::= expr likeop expr */
+  {  185,   -5 }, /* (189) expr ::= expr likeop expr ESCAPE expr */
+  {  185,   -2 }, /* (190) expr ::= expr ISNULL|NOTNULL */
+  {  185,   -3 }, /* (191) expr ::= expr NOT NULL */
+  {  185,   -3 }, /* (192) expr ::= expr IS expr */
+  {  185,   -4 }, /* (193) expr ::= expr IS NOT expr */
+  {  185,   -2 }, /* (194) expr ::= NOT expr */
+  {  185,   -2 }, /* (195) expr ::= BITNOT expr */
+  {  185,   -2 }, /* (196) expr ::= PLUS|MINUS expr */
+  {  239,   -1 }, /* (197) between_op ::= BETWEEN */
+  {  239,   -2 }, /* (198) between_op ::= NOT BETWEEN */
+  {  185,   -5 }, /* (199) expr ::= expr between_op expr AND expr */
+  {  240,   -1 }, /* (200) in_op ::= IN */
+  {  240,   -2 }, /* (201) in_op ::= NOT IN */
+  {  185,   -5 }, /* (202) expr ::= expr in_op LP exprlist RP */
+  {  185,   -3 }, /* (203) expr ::= LP select RP */
+  {  185,   -5 }, /* (204) expr ::= expr in_op LP select RP */
+  {  185,   -5 }, /* (205) expr ::= expr in_op nm dbnm paren_exprlist */
+  {  185,   -4 }, /* (206) expr ::= EXISTS LP select RP */
+  {  185,   -5 }, /* (207) expr ::= CASE case_operand case_exprlist case_else END */
+  {  243,   -5 }, /* (208) case_exprlist ::= case_exprlist WHEN expr THEN expr */
+  {  243,   -4 }, /* (209) case_exprlist ::= WHEN expr THEN expr */
+  {  244,   -2 }, /* (210) case_else ::= ELSE expr */
+  {  244,    0 }, /* (211) case_else ::= */
+  {  242,   -1 }, /* (212) case_operand ::= expr */
+  {  242,    0 }, /* (213) case_operand ::= */
+  {  229,    0 }, /* (214) exprlist ::= */
+  {  220,   -3 }, /* (215) nexprlist ::= nexprlist COMMA expr */
+  {  220,   -1 }, /* (216) nexprlist ::= expr */
+  {  241,    0 }, /* (217) paren_exprlist ::= */
+  {  241,   -3 }, /* (218) paren_exprlist ::= LP exprlist RP */
+  {  160,  -12 }, /* (219) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
+  {  245,   -1 }, /* (220) uniqueflag ::= UNIQUE */
+  {  245,    0 }, /* (221) uniqueflag ::= */
+  {  189,    0 }, /* (222) eidlist_opt ::= */
+  {  189,   -3 }, /* (223) eidlist_opt ::= LP eidlist RP */
+  {  199,   -5 }, /* (224) eidlist ::= eidlist COMMA nm collate sortorder */
+  {  199,   -3 }, /* (225) eidlist ::= nm collate sortorder */
+  {  246,    0 }, /* (226) collate ::= */
+  {  246,   -2 }, /* (227) collate ::= COLLATE ID|STRING */
+  {  160,   -4 }, /* (228) cmd ::= DROP INDEX ifexists fullname */
+  {  160,   -1 }, /* (229) cmd ::= VACUUM */
+  {  160,   -2 }, /* (230) cmd ::= VACUUM nm */
+  {  160,   -3 }, /* (231) cmd ::= PRAGMA nm dbnm */
+  {  160,   -5 }, /* (232) cmd ::= PRAGMA nm dbnm EQ nmnum */
+  {  160,   -6 }, /* (233) cmd ::= PRAGMA nm dbnm LP nmnum RP */
+  {  160,   -5 }, /* (234) cmd ::= PRAGMA nm dbnm EQ minus_num */
+  {  160,   -6 }, /* (235) cmd ::= PRAGMA nm dbnm LP minus_num RP */
+  {  180,   -2 }, /* (236) plus_num ::= PLUS INTEGER|FLOAT */
+  {  181,   -2 }, /* (237) minus_num ::= MINUS INTEGER|FLOAT */
+  {  160,   -5 }, /* (238) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
+  {  248,  -11 }, /* (239) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+  {  250,   -1 }, /* (240) trigger_time ::= BEFORE|AFTER */
+  {  250,   -2 }, /* (241) trigger_time ::= INSTEAD OF */
+  {  250,    0 }, /* (242) trigger_time ::= */
+  {  251,   -1 }, /* (243) trigger_event ::= DELETE|INSERT */
+  {  251,   -1 }, /* (244) trigger_event ::= UPDATE */
+  {  251,   -3 }, /* (245) trigger_event ::= UPDATE OF idlist */
+  {  253,    0 }, /* (246) when_clause ::= */
+  {  253,   -2 }, /* (247) when_clause ::= WHEN expr */
+  {  249,   -3 }, /* (248) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+  {  249,   -2 }, /* (249) trigger_cmd_list ::= trigger_cmd SEMI */
+  {  255,   -3 }, /* (250) trnm ::= nm DOT nm */
+  {  256,   -3 }, /* (251) tridxby ::= INDEXED BY nm */
+  {  256,   -2 }, /* (252) tridxby ::= NOT INDEXED */
+  {  254,   -8 }, /* (253) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */
+  {  254,   -8 }, /* (254) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
+  {  254,   -6 }, /* (255) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
+  {  254,   -3 }, /* (256) trigger_cmd ::= scanpt select scanpt */
+  {  185,   -4 }, /* (257) expr ::= RAISE LP IGNORE RP */
+  {  185,   -6 }, /* (258) expr ::= RAISE LP raisetype COMMA nm RP */
+  {  203,   -1 }, /* (259) raisetype ::= ROLLBACK */
+  {  203,   -1 }, /* (260) raisetype ::= ABORT */
+  {  203,   -1 }, /* (261) raisetype ::= FAIL */
+  {  160,   -4 }, /* (262) cmd ::= DROP TRIGGER ifexists fullname */
+  {  160,   -6 }, /* (263) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+  {  160,   -3 }, /* (264) cmd ::= DETACH database_kw_opt expr */
+  {  258,    0 }, /* (265) key_opt ::= */
+  {  258,   -2 }, /* (266) key_opt ::= KEY expr */
+  {  160,   -1 }, /* (267) cmd ::= REINDEX */
+  {  160,   -3 }, /* (268) cmd ::= REINDEX nm dbnm */
+  {  160,   -1 }, /* (269) cmd ::= ANALYZE */
+  {  160,   -3 }, /* (270) cmd ::= ANALYZE nm dbnm */
+  {  160,   -6 }, /* (271) cmd ::= ALTER TABLE fullname RENAME TO nm */
+  {  160,   -7 }, /* (272) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
+  {  259,   -1 }, /* (273) add_column_fullname ::= fullname */
+  {  160,   -8 }, /* (274) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
+  {  160,   -1 }, /* (275) cmd ::= create_vtab */
+  {  160,   -4 }, /* (276) cmd ::= create_vtab LP vtabarglist RP */
+  {  261,   -8 }, /* (277) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
+  {  263,    0 }, /* (278) vtabarg ::= */
+  {  264,   -1 }, /* (279) vtabargtoken ::= ANY */
+  {  264,   -3 }, /* (280) vtabargtoken ::= lp anylist RP */
+  {  265,   -1 }, /* (281) lp ::= LP */
+  {  232,   -2 }, /* (282) with ::= WITH wqlist */
+  {  232,   -3 }, /* (283) with ::= WITH RECURSIVE wqlist */
+  {  208,   -6 }, /* (284) wqlist ::= nm eidlist_opt AS LP select RP */
+  {  208,   -8 }, /* (285) wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
+  {  267,   -1 }, /* (286) windowdefn_list ::= windowdefn */
+  {  267,   -3 }, /* (287) windowdefn_list ::= windowdefn_list COMMA windowdefn */
+  {  268,   -3 }, /* (288) windowdefn ::= nm AS window */
+  {  269,   -5 }, /* (289) window ::= LP part_opt orderby_opt frame_opt RP */
+  {  271,   -3 }, /* (290) part_opt ::= PARTITION BY nexprlist */
+  {  271,    0 }, /* (291) part_opt ::= */
+  {  270,    0 }, /* (292) frame_opt ::= */
+  {  270,   -2 }, /* (293) frame_opt ::= range_or_rows frame_bound_s */
+  {  270,   -5 }, /* (294) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e */
+  {  273,   -1 }, /* (295) range_or_rows ::= RANGE */
+  {  273,   -1 }, /* (296) range_or_rows ::= ROWS */
+  {  275,   -1 }, /* (297) frame_bound_s ::= frame_bound */
+  {  275,   -2 }, /* (298) frame_bound_s ::= UNBOUNDED PRECEDING */
+  {  276,   -1 }, /* (299) frame_bound_e ::= frame_bound */
+  {  276,   -2 }, /* (300) frame_bound_e ::= UNBOUNDED FOLLOWING */
+  {  274,   -2 }, /* (301) frame_bound ::= expr PRECEDING */
+  {  274,   -2 }, /* (302) frame_bound ::= CURRENT ROW */
+  {  274,   -2 }, /* (303) frame_bound ::= expr FOLLOWING */
+  {  218,   -2 }, /* (304) window_clause ::= WINDOW windowdefn_list */
+  {  237,   -3 }, /* (305) over_clause ::= filter_opt OVER window */
+  {  237,   -3 }, /* (306) over_clause ::= filter_opt OVER nm */
+  {  272,    0 }, /* (307) filter_opt ::= */
+  {  272,   -5 }, /* (308) filter_opt ::= FILTER LP WHERE expr RP */
+  {  155,   -1 }, /* (309) input ::= cmdlist */
+  {  156,   -2 }, /* (310) cmdlist ::= cmdlist ecmd */
+  {  156,   -1 }, /* (311) cmdlist ::= ecmd */
+  {  157,   -1 }, /* (312) ecmd ::= SEMI */
+  {  157,   -2 }, /* (313) ecmd ::= cmdx SEMI */
+  {  157,   -2 }, /* (314) ecmd ::= explain cmdx */
+  {  162,    0 }, /* (315) trans_opt ::= */
+  {  162,   -1 }, /* (316) trans_opt ::= TRANSACTION */
+  {  162,   -2 }, /* (317) trans_opt ::= TRANSACTION nm */
+  {  164,   -1 }, /* (318) savepoint_opt ::= SAVEPOINT */
+  {  164,    0 }, /* (319) savepoint_opt ::= */
+  {  160,   -2 }, /* (320) cmd ::= create_table create_table_args */
+  {  171,   -4 }, /* (321) columnlist ::= columnlist COMMA columnname carglist */
+  {  171,   -2 }, /* (322) columnlist ::= columnname carglist */
+  {  163,   -1 }, /* (323) nm ::= ID|INDEXED */
+  {  163,   -1 }, /* (324) nm ::= STRING */
+  {  163,   -1 }, /* (325) nm ::= JOIN_KW */
+  {  177,   -1 }, /* (326) typetoken ::= typename */
+  {  178,   -1 }, /* (327) typename ::= ID|STRING */
+  {  179,   -1 }, /* (328) signed ::= plus_num */
+  {  179,   -1 }, /* (329) signed ::= minus_num */
+  {  176,   -2 }, /* (330) carglist ::= carglist ccons */
+  {  176,    0 }, /* (331) carglist ::= */
+  {  183,   -2 }, /* (332) ccons ::= NULL onconf */
+  {  172,   -2 }, /* (333) conslist_opt ::= COMMA conslist */
+  {  195,   -3 }, /* (334) conslist ::= conslist tconscomma tcons */
+  {  195,   -1 }, /* (335) conslist ::= tcons */
+  {  196,    0 }, /* (336) tconscomma ::= */
+  {  200,   -1 }, /* (337) defer_subclause_opt ::= defer_subclause */
+  {  202,   -1 }, /* (338) resolvetype ::= raisetype */
+  {  206,   -1 }, /* (339) selectnowith ::= oneselect */
+  {  207,   -1 }, /* (340) oneselect ::= values */
+  {  221,   -2 }, /* (341) sclp ::= selcollist COMMA */
+  {  222,   -1 }, /* (342) as ::= ID|STRING */
+  {  185,   -1 }, /* (343) expr ::= term */
+  {  238,   -1 }, /* (344) likeop ::= LIKE_KW|MATCH */
+  {  229,   -1 }, /* (345) exprlist ::= nexprlist */
+  {  247,   -1 }, /* (346) nmnum ::= plus_num */
+  {  247,   -1 }, /* (347) nmnum ::= nm */
+  {  247,   -1 }, /* (348) nmnum ::= ON */
+  {  247,   -1 }, /* (349) nmnum ::= DELETE */
+  {  247,   -1 }, /* (350) nmnum ::= DEFAULT */
+  {  180,   -1 }, /* (351) plus_num ::= INTEGER|FLOAT */
+  {  252,    0 }, /* (352) foreach_clause ::= */
+  {  252,   -3 }, /* (353) foreach_clause ::= FOR EACH ROW */
+  {  255,   -1 }, /* (354) trnm ::= nm */
+  {  256,    0 }, /* (355) tridxby ::= */
+  {  257,   -1 }, /* (356) database_kw_opt ::= DATABASE */
+  {  257,    0 }, /* (357) database_kw_opt ::= */
+  {  260,    0 }, /* (358) kwcolumn_opt ::= */
+  {  260,   -1 }, /* (359) kwcolumn_opt ::= COLUMNKW */
+  {  262,   -1 }, /* (360) vtabarglist ::= vtabarg */
+  {  262,   -3 }, /* (361) vtabarglist ::= vtabarglist COMMA vtabarg */
+  {  263,   -2 }, /* (362) vtabarg ::= vtabarg vtabargtoken */
+  {  266,    0 }, /* (363) anylist ::= */
+  {  266,   -4 }, /* (364) anylist ::= anylist LP anylist RP */
+  {  266,   -2 }, /* (365) anylist ::= anylist ANY */
+  {  232,    0 }, /* (366) with ::= */
 };
 
 static void yy_accept(yyParser*);  /* Forward Declaration */
@@ -143862,7 +148558,7 @@ static YYACTIONTYPE yy_reduce(
   sqlite3ParserCTX_PDECL                   /* %extra_context */
 ){
   int yygoto;                     /* The next state */
-  int yyact;                      /* The next action */
+  YYACTIONTYPE yyact;             /* The next action */
   yyStackEntry *yymsp;            /* The top of the parser's stack */
   int yysize;                     /* Amount to pop the stack */
   sqlite3ParserARG_FETCH
@@ -143936,15 +148632,15 @@ static YYACTIONTYPE yy_reduce(
 { sqlite3FinishCoding(pParse); }
         break;
       case 3: /* cmd ::= BEGIN transtype trans_opt */
-{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy502);}
+{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy70);}
         break;
       case 4: /* transtype ::= */
-{yymsp[1].minor.yy502 = TK_DEFERRED;}
+{yymsp[1].minor.yy70 = TK_DEFERRED;}
         break;
       case 5: /* transtype ::= DEFERRED */
       case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6);
       case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7);
-{yymsp[0].minor.yy502 = yymsp[0].major; /*A-overwrites-X*/}
+{yymsp[0].minor.yy70 = yymsp[0].major; /*A-overwrites-X*/}
         break;
       case 8: /* cmd ::= COMMIT|END trans_opt */
       case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9);
@@ -143967,7 +148663,7 @@ static YYACTIONTYPE yy_reduce(
         break;
       case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
 {
-   sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy502,0,0,yymsp[-2].minor.yy502);
+   sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy70,0,0,yymsp[-2].minor.yy70);
 }
         break;
       case 14: /* createkw ::= CREATE */
@@ -143980,34 +148676,34 @@ static YYACTIONTYPE yy_reduce(
       case 57: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==57);
       case 67: /* defer_subclause_opt ::= */ yytestcase(yyruleno==67);
       case 76: /* ifexists ::= */ yytestcase(yyruleno==76);
-      case 92: /* distinct ::= */ yytestcase(yyruleno==92);
-      case 224: /* collate ::= */ yytestcase(yyruleno==224);
-{yymsp[1].minor.yy502 = 0;}
+      case 93: /* distinct ::= */ yytestcase(yyruleno==93);
+      case 226: /* collate ::= */ yytestcase(yyruleno==226);
+{yymsp[1].minor.yy70 = 0;}
         break;
       case 16: /* ifnotexists ::= IF NOT EXISTS */
-{yymsp[-2].minor.yy502 = 1;}
+{yymsp[-2].minor.yy70 = 1;}
         break;
       case 17: /* temp ::= TEMP */
       case 43: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==43);
-{yymsp[0].minor.yy502 = 1;}
+{yymsp[0].minor.yy70 = 1;}
         break;
       case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_options */
 {
-  sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy502,0);
+  sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy70,0);
 }
         break;
       case 20: /* create_table_args ::= AS select */
 {
-  sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy399);
-  sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy399);
+  sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy489);
+  sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy489);
 }
         break;
       case 22: /* table_options ::= WITHOUT nm */
 {
   if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){
-    yymsp[-1].minor.yy502 = TF_WithoutRowid | TF_NoVisibleRowid;
+    yymsp[-1].minor.yy70 = TF_WithoutRowid | TF_NoVisibleRowid;
   }else{
-    yymsp[-1].minor.yy502 = 0;
+    yymsp[-1].minor.yy70 = 0;
     sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z);
   }
 }
@@ -144017,7 +148713,7 @@ static YYACTIONTYPE yy_reduce(
         break;
       case 24: /* typetoken ::= */
       case 60: /* conslist_opt ::= */ yytestcase(yyruleno==60);
-      case 98: /* as ::= */ yytestcase(yyruleno==98);
+      case 99: /* as ::= */ yytestcase(yyruleno==99);
 {yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;}
         break;
       case 25: /* typetoken ::= typename LP signed RP */
@@ -144036,7 +148732,7 @@ static YYACTIONTYPE yy_reduce(
       case 28: /* scanpt ::= */
 {
   assert( yyLookahead!=YYNOCODE );
-  yymsp[1].minor.yy36 = yyLookaheadToken.z;
+  yymsp[1].minor.yy392 = yyLookaheadToken.z;
 }
         break;
       case 29: /* ccons ::= CONSTRAINT nm */
@@ -144044,18 +148740,18 @@ static YYACTIONTYPE yy_reduce(
 {pParse->constraintName = yymsp[0].minor.yy0;}
         break;
       case 30: /* ccons ::= DEFAULT scanpt term scanpt */
-{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy182,yymsp[-2].minor.yy36,yymsp[0].minor.yy36);}
+{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy18,yymsp[-2].minor.yy392,yymsp[0].minor.yy392);}
         break;
       case 31: /* ccons ::= DEFAULT LP expr RP */
-{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy182,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);}
+{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy18,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);}
         break;
       case 32: /* ccons ::= DEFAULT PLUS term scanpt */
-{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy182,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy36);}
+{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy18,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy392);}
         break;
       case 33: /* ccons ::= DEFAULT MINUS term scanpt */
 {
-  Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[-1].minor.yy182, 0);
-  sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy36);
+  Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[-1].minor.yy18, 0);
+  sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy392);
 }
         break;
       case 34: /* ccons ::= DEFAULT scanpt ID|INDEXED */
@@ -144065,174 +148761,174 @@ static YYACTIONTYPE yy_reduce(
     sqlite3ExprIdToTrueFalse(p);
     testcase( p->op==TK_TRUEFALSE && sqlite3ExprTruthValue(p) );
   }
-  sqlite3AddDefaultValue(pParse,p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.z+yymsp[0].minor.yy0.n);
+    sqlite3AddDefaultValue(pParse,p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.z+yymsp[0].minor.yy0.n);
 }
         break;
       case 35: /* ccons ::= NOT NULL onconf */
-{sqlite3AddNotNull(pParse, yymsp[0].minor.yy502);}
+{sqlite3AddNotNull(pParse, yymsp[0].minor.yy70);}
         break;
       case 36: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
-{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy502,yymsp[0].minor.yy502,yymsp[-2].minor.yy502);}
+{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy70,yymsp[0].minor.yy70,yymsp[-2].minor.yy70);}
         break;
       case 37: /* ccons ::= UNIQUE onconf */
-{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy502,0,0,0,0,
+{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy70,0,0,0,0,
                                    SQLITE_IDXTYPE_UNIQUE);}
         break;
       case 38: /* ccons ::= CHECK LP expr RP */
-{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy182);}
+{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy18);}
         break;
       case 39: /* ccons ::= REFERENCES nm eidlist_opt refargs */
-{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy232,yymsp[0].minor.yy502);}
+{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy420,yymsp[0].minor.yy70);}
         break;
       case 40: /* ccons ::= defer_subclause */
-{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy502);}
+{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy70);}
         break;
       case 41: /* ccons ::= COLLATE ID|STRING */
 {sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);}
         break;
       case 44: /* refargs ::= */
-{ yymsp[1].minor.yy502 = OE_None*0x0101; /* EV: R-19803-45884 */}
+{ yymsp[1].minor.yy70 = OE_None*0x0101; /* EV: R-19803-45884 */}
         break;
       case 45: /* refargs ::= refargs refarg */
-{ yymsp[-1].minor.yy502 = (yymsp[-1].minor.yy502 & ~yymsp[0].minor.yy107.mask) | yymsp[0].minor.yy107.value; }
+{ yymsp[-1].minor.yy70 = (yymsp[-1].minor.yy70 & ~yymsp[0].minor.yy111.mask) | yymsp[0].minor.yy111.value; }
         break;
       case 46: /* refarg ::= MATCH nm */
-{ yymsp[-1].minor.yy107.value = 0;     yymsp[-1].minor.yy107.mask = 0x000000; }
+{ yymsp[-1].minor.yy111.value = 0;     yymsp[-1].minor.yy111.mask = 0x000000; }
         break;
       case 47: /* refarg ::= ON INSERT refact */
-{ yymsp[-2].minor.yy107.value = 0;     yymsp[-2].minor.yy107.mask = 0x000000; }
+{ yymsp[-2].minor.yy111.value = 0;     yymsp[-2].minor.yy111.mask = 0x000000; }
         break;
       case 48: /* refarg ::= ON DELETE refact */
-{ yymsp[-2].minor.yy107.value = yymsp[0].minor.yy502;     yymsp[-2].minor.yy107.mask = 0x0000ff; }
+{ yymsp[-2].minor.yy111.value = yymsp[0].minor.yy70;     yymsp[-2].minor.yy111.mask = 0x0000ff; }
         break;
       case 49: /* refarg ::= ON UPDATE refact */
-{ yymsp[-2].minor.yy107.value = yymsp[0].minor.yy502<<8;  yymsp[-2].minor.yy107.mask = 0x00ff00; }
+{ yymsp[-2].minor.yy111.value = yymsp[0].minor.yy70<<8;  yymsp[-2].minor.yy111.mask = 0x00ff00; }
         break;
       case 50: /* refact ::= SET NULL */
-{ yymsp[-1].minor.yy502 = OE_SetNull;  /* EV: R-33326-45252 */}
+{ yymsp[-1].minor.yy70 = OE_SetNull;  /* EV: R-33326-45252 */}
         break;
       case 51: /* refact ::= SET DEFAULT */
-{ yymsp[-1].minor.yy502 = OE_SetDflt;  /* EV: R-33326-45252 */}
+{ yymsp[-1].minor.yy70 = OE_SetDflt;  /* EV: R-33326-45252 */}
         break;
       case 52: /* refact ::= CASCADE */
-{ yymsp[0].minor.yy502 = OE_Cascade;  /* EV: R-33326-45252 */}
+{ yymsp[0].minor.yy70 = OE_Cascade;  /* EV: R-33326-45252 */}
         break;
       case 53: /* refact ::= RESTRICT */
-{ yymsp[0].minor.yy502 = OE_Restrict; /* EV: R-33326-45252 */}
+{ yymsp[0].minor.yy70 = OE_Restrict; /* EV: R-33326-45252 */}
         break;
       case 54: /* refact ::= NO ACTION */
-{ yymsp[-1].minor.yy502 = OE_None;     /* EV: R-33326-45252 */}
+{ yymsp[-1].minor.yy70 = OE_None;     /* EV: R-33326-45252 */}
         break;
       case 55: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
-{yymsp[-2].minor.yy502 = 0;}
+{yymsp[-2].minor.yy70 = 0;}
         break;
       case 56: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
       case 71: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==71);
-      case 155: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==155);
-{yymsp[-1].minor.yy502 = yymsp[0].minor.yy502;}
+      case 156: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==156);
+{yymsp[-1].minor.yy70 = yymsp[0].minor.yy70;}
         break;
       case 58: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */
       case 75: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==75);
-      case 196: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==196);
-      case 199: /* in_op ::= NOT IN */ yytestcase(yyruleno==199);
-      case 225: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==225);
-{yymsp[-1].minor.yy502 = 1;}
+      case 198: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==198);
+      case 201: /* in_op ::= NOT IN */ yytestcase(yyruleno==201);
+      case 227: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==227);
+{yymsp[-1].minor.yy70 = 1;}
         break;
       case 59: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
-{yymsp[-1].minor.yy502 = 0;}
+{yymsp[-1].minor.yy70 = 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.yy232,yymsp[0].minor.yy502,yymsp[-2].minor.yy502,0);}
+{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy420,yymsp[0].minor.yy70,yymsp[-2].minor.yy70,0);}
         break;
       case 64: /* tcons ::= UNIQUE LP sortlist RP onconf */
-{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy232,yymsp[0].minor.yy502,0,0,0,0,
+{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy420,yymsp[0].minor.yy70,0,0,0,0,
                                        SQLITE_IDXTYPE_UNIQUE);}
         break;
       case 65: /* tcons ::= CHECK LP expr RP onconf */
-{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy182);}
+{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy18);}
         break;
       case 66: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
 {
-    sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy232, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy232, yymsp[-1].minor.yy502);
-    sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy502);
+    sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy420, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy420, yymsp[-1].minor.yy70);
+    sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy70);
 }
         break;
       case 68: /* onconf ::= */
       case 70: /* orconf ::= */ yytestcase(yyruleno==70);
-{yymsp[1].minor.yy502 = OE_Default;}
+{yymsp[1].minor.yy70 = OE_Default;}
         break;
       case 69: /* onconf ::= ON CONFLICT resolvetype */
-{yymsp[-2].minor.yy502 = yymsp[0].minor.yy502;}
+{yymsp[-2].minor.yy70 = yymsp[0].minor.yy70;}
         break;
       case 72: /* resolvetype ::= IGNORE */
-{yymsp[0].minor.yy502 = OE_Ignore;}
+{yymsp[0].minor.yy70 = OE_Ignore;}
         break;
       case 73: /* resolvetype ::= REPLACE */
-      case 156: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==156);
-{yymsp[0].minor.yy502 = OE_Replace;}
+      case 157: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==157);
+{yymsp[0].minor.yy70 = OE_Replace;}
         break;
       case 74: /* cmd ::= DROP TABLE ifexists fullname */
 {
-  sqlite3DropTable(pParse, yymsp[0].minor.yy427, 0, yymsp[-1].minor.yy502);
+  sqlite3DropTable(pParse, yymsp[0].minor.yy135, 0, yymsp[-1].minor.yy70);
 }
         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.yy232, yymsp[0].minor.yy399, yymsp[-7].minor.yy502, yymsp[-5].minor.yy502);
+  sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy420, yymsp[0].minor.yy489, yymsp[-7].minor.yy70, yymsp[-5].minor.yy70);
 }
         break;
       case 78: /* cmd ::= DROP VIEW ifexists fullname */
 {
-  sqlite3DropTable(pParse, yymsp[0].minor.yy427, 1, yymsp[-1].minor.yy502);
+  sqlite3DropTable(pParse, yymsp[0].minor.yy135, 1, yymsp[-1].minor.yy70);
 }
         break;
       case 79: /* cmd ::= select */
 {
   SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0};
-  sqlite3Select(pParse, yymsp[0].minor.yy399, &dest);
-  sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy399);
+  sqlite3Select(pParse, yymsp[0].minor.yy489, &dest);
+  sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy489);
 }
         break;
       case 80: /* select ::= WITH wqlist selectnowith */
 {
-  Select *p = yymsp[0].minor.yy399;
+  Select *p = yymsp[0].minor.yy489;
   if( p ){
-    p->pWith = yymsp[-1].minor.yy91;
+    p->pWith = yymsp[-1].minor.yy449;
     parserDoubleLinkSelect(pParse, p);
   }else{
-    sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy91);
+    sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy449);
   }
-  yymsp[-2].minor.yy399 = p;
+  yymsp[-2].minor.yy489 = p;
 }
         break;
       case 81: /* select ::= WITH RECURSIVE wqlist selectnowith */
 {
-  Select *p = yymsp[0].minor.yy399;
+  Select *p = yymsp[0].minor.yy489;
   if( p ){
-    p->pWith = yymsp[-1].minor.yy91;
+    p->pWith = yymsp[-1].minor.yy449;
     parserDoubleLinkSelect(pParse, p);
   }else{
-    sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy91);
+    sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy449);
   }
-  yymsp[-3].minor.yy399 = p;
+  yymsp[-3].minor.yy489 = p;
 }
         break;
       case 82: /* select ::= selectnowith */
 {
-  Select *p = yymsp[0].minor.yy399;
+  Select *p = yymsp[0].minor.yy489;
   if( p ){
     parserDoubleLinkSelect(pParse, p);
   }
-  yymsp[0].minor.yy399 = p; /*A-overwrites-X*/
+  yymsp[0].minor.yy489 = p; /*A-overwrites-X*/
 }
         break;
       case 83: /* selectnowith ::= selectnowith multiselect_op oneselect */
 {
-  Select *pRhs = yymsp[0].minor.yy399;
-  Select *pLhs = yymsp[-2].minor.yy399;
+  Select *pRhs = yymsp[0].minor.yy489;
+  Select *pLhs = yymsp[-2].minor.yy489;
   if( pRhs && pRhs->pPrior ){
     SrcList *pFrom;
     Token x;
@@ -144242,378 +148938,382 @@ static YYACTIONTYPE yy_reduce(
     pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0);
   }
   if( pRhs ){
-    pRhs->op = (u8)yymsp[-1].minor.yy502;
+    pRhs->op = (u8)yymsp[-1].minor.yy70;
     pRhs->pPrior = pLhs;
     if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue;
     pRhs->selFlags &= ~SF_MultiValue;
-    if( yymsp[-1].minor.yy502!=TK_ALL ) pParse->hasCompound = 1;
+    if( yymsp[-1].minor.yy70!=TK_ALL ) pParse->hasCompound = 1;
   }else{
     sqlite3SelectDelete(pParse->db, pLhs);
   }
-  yymsp[-2].minor.yy399 = pRhs;
+  yymsp[-2].minor.yy489 = pRhs;
 }
         break;
       case 84: /* multiselect_op ::= UNION */
       case 86: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==86);
-{yymsp[0].minor.yy502 = yymsp[0].major; /*A-overwrites-OP*/}
+{yymsp[0].minor.yy70 = yymsp[0].major; /*A-overwrites-OP*/}
         break;
       case 85: /* multiselect_op ::= UNION ALL */
-{yymsp[-1].minor.yy502 = TK_ALL;}
+{yymsp[-1].minor.yy70 = TK_ALL;}
         break;
       case 87: /* 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.yy399 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy232,yymsp[-5].minor.yy427,yymsp[-4].minor.yy182,yymsp[-3].minor.yy232,yymsp[-2].minor.yy182,yymsp[-1].minor.yy232,yymsp[-7].minor.yy502,yymsp[0].minor.yy182);
-#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.yy399!=0 ){
-    const char *z = s.z+6;
-    int i;
-    sqlite3_snprintf(sizeof(yymsp[-8].minor.yy399->zSelName), yymsp[-8].minor.yy399->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.yy399->zSelName), yymsp[-8].minor.yy399->zSelName, "%.*s", i, z);
-    }
+  yymsp[-8].minor.yy489 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy420,yymsp[-5].minor.yy135,yymsp[-4].minor.yy18,yymsp[-3].minor.yy420,yymsp[-2].minor.yy18,yymsp[-1].minor.yy420,yymsp[-7].minor.yy70,yymsp[0].minor.yy18);
+}
+        break;
+      case 88: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
+{
+  yymsp[-9].minor.yy489 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy420,yymsp[-6].minor.yy135,yymsp[-5].minor.yy18,yymsp[-4].minor.yy420,yymsp[-3].minor.yy18,yymsp[-1].minor.yy420,yymsp[-8].minor.yy70,yymsp[0].minor.yy18);
+  if( yymsp[-9].minor.yy489 ){
+    yymsp[-9].minor.yy489->pWinDefn = yymsp[-2].minor.yy327;
+  }else{
+    sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy327);
   }
-#endif /* SELECTRACE_ENABLED */
 }
         break;
-      case 88: /* values ::= VALUES LP nexprlist RP */
+      case 89: /* values ::= VALUES LP nexprlist RP */
 {
-  yymsp[-3].minor.yy399 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy232,0,0,0,0,0,SF_Values,0);
+  yymsp[-3].minor.yy489 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy420,0,0,0,0,0,SF_Values,0);
 }
         break;
-      case 89: /* values ::= values COMMA LP exprlist RP */
+      case 90: /* values ::= values COMMA LP nexprlist RP */
 {
-  Select *pRight, *pLeft = yymsp[-4].minor.yy399;
-  pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy232,0,0,0,0,0,SF_Values|SF_MultiValue,0);
+  Select *pRight, *pLeft = yymsp[-4].minor.yy489;
+  pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy420,0,0,0,0,0,SF_Values|SF_MultiValue,0);
   if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue;
   if( pRight ){
     pRight->op = TK_ALL;
     pRight->pPrior = pLeft;
-    yymsp[-4].minor.yy399 = pRight;
+    yymsp[-4].minor.yy489 = pRight;
   }else{
-    yymsp[-4].minor.yy399 = pLeft;
+    yymsp[-4].minor.yy489 = pLeft;
   }
 }
         break;
-      case 90: /* distinct ::= DISTINCT */
-{yymsp[0].minor.yy502 = SF_Distinct;}
+      case 91: /* distinct ::= DISTINCT */
+{yymsp[0].minor.yy70 = SF_Distinct;}
         break;
-      case 91: /* distinct ::= ALL */
-{yymsp[0].minor.yy502 = SF_All;}
+      case 92: /* distinct ::= ALL */
+{yymsp[0].minor.yy70 = SF_All;}
         break;
-      case 93: /* sclp ::= */
-      case 126: /* orderby_opt ::= */ yytestcase(yyruleno==126);
-      case 133: /* groupby_opt ::= */ yytestcase(yyruleno==133);
-      case 212: /* exprlist ::= */ yytestcase(yyruleno==212);
-      case 215: /* paren_exprlist ::= */ yytestcase(yyruleno==215);
-      case 220: /* eidlist_opt ::= */ yytestcase(yyruleno==220);
-{yymsp[1].minor.yy232 = 0;}
+      case 94: /* sclp ::= */
+      case 127: /* orderby_opt ::= */ yytestcase(yyruleno==127);
+      case 134: /* groupby_opt ::= */ yytestcase(yyruleno==134);
+      case 214: /* exprlist ::= */ yytestcase(yyruleno==214);
+      case 217: /* paren_exprlist ::= */ yytestcase(yyruleno==217);
+      case 222: /* eidlist_opt ::= */ yytestcase(yyruleno==222);
+{yymsp[1].minor.yy420 = 0;}
         break;
-      case 94: /* selcollist ::= sclp scanpt expr scanpt as */
+      case 95: /* selcollist ::= sclp scanpt expr scanpt as */
 {
-   yymsp[-4].minor.yy232 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy232, yymsp[-2].minor.yy182);
-   if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy232, &yymsp[0].minor.yy0, 1);
-   sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy232,yymsp[-3].minor.yy36,yymsp[-1].minor.yy36);
+   yymsp[-4].minor.yy420 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy420, yymsp[-2].minor.yy18);
+   if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy420, &yymsp[0].minor.yy0, 1);
+   sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy420,yymsp[-3].minor.yy392,yymsp[-1].minor.yy392);
 }
         break;
-      case 95: /* selcollist ::= sclp scanpt STAR */
+      case 96: /* selcollist ::= sclp scanpt STAR */
 {
   Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0);
-  yymsp[-2].minor.yy232 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy232, p);
+  yymsp[-2].minor.yy420 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy420, p);
 }
         break;
-      case 96: /* selcollist ::= sclp scanpt nm DOT STAR */
+      case 97: /* selcollist ::= sclp scanpt nm DOT STAR */
 {
   Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0);
   Expr *pLeft = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
   Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
-  yymsp[-4].minor.yy232 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy232, pDot);
+  yymsp[-4].minor.yy420 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy420, pDot);
 }
         break;
-      case 97: /* as ::= AS nm */
-      case 108: /* dbnm ::= DOT nm */ yytestcase(yyruleno==108);
-      case 234: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==234);
-      case 235: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==235);
+      case 98: /* as ::= AS nm */
+      case 109: /* dbnm ::= DOT nm */ yytestcase(yyruleno==109);
+      case 236: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==236);
+      case 237: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==237);
 {yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;}
         break;
-      case 99: /* from ::= */
-{yymsp[1].minor.yy427 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy427));}
+      case 100: /* from ::= */
+{yymsp[1].minor.yy135 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy135));}
         break;
-      case 100: /* from ::= FROM seltablist */
+      case 101: /* from ::= FROM seltablist */
 {
-  yymsp[-1].minor.yy427 = yymsp[0].minor.yy427;
-  sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy427);
+  yymsp[-1].minor.yy135 = yymsp[0].minor.yy135;
+  sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy135);
 }
         break;
-      case 101: /* stl_prefix ::= seltablist joinop */
+      case 102: /* stl_prefix ::= seltablist joinop */
 {
-   if( ALWAYS(yymsp[-1].minor.yy427 && yymsp[-1].minor.yy427->nSrc>0) ) yymsp[-1].minor.yy427->a[yymsp[-1].minor.yy427->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy502;
+   if( ALWAYS(yymsp[-1].minor.yy135 && yymsp[-1].minor.yy135->nSrc>0) ) yymsp[-1].minor.yy135->a[yymsp[-1].minor.yy135->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy70;
 }
         break;
-      case 102: /* stl_prefix ::= */
-{yymsp[1].minor.yy427 = 0;}
+      case 103: /* stl_prefix ::= */
+{yymsp[1].minor.yy135 = 0;}
         break;
-      case 103: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
+      case 104: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
 {
-  yymsp[-6].minor.yy427 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy427,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy182,yymsp[0].minor.yy510);
-  sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy427, &yymsp[-2].minor.yy0);
+  yymsp[-6].minor.yy135 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy135,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy18,yymsp[0].minor.yy48);
+  sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy135, &yymsp[-2].minor.yy0);
 }
         break;
-      case 104: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
+      case 105: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
 {
-  yymsp[-8].minor.yy427 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy427,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy182,yymsp[0].minor.yy510);
-  sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy427, yymsp[-4].minor.yy232);
+  yymsp[-8].minor.yy135 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy135,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy18,yymsp[0].minor.yy48);
+  sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy135, yymsp[-4].minor.yy420);
 }
         break;
-      case 105: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */
+      case 106: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */
 {
-    yymsp[-6].minor.yy427 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy427,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy399,yymsp[-1].minor.yy182,yymsp[0].minor.yy510);
+    yymsp[-6].minor.yy135 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy135,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy489,yymsp[-1].minor.yy18,yymsp[0].minor.yy48);
   }
         break;
-      case 106: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
+      case 107: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
 {
-    if( yymsp[-6].minor.yy427==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy182==0 && yymsp[0].minor.yy510==0 ){
-      yymsp[-6].minor.yy427 = yymsp[-4].minor.yy427;
-    }else if( yymsp[-4].minor.yy427->nSrc==1 ){
-      yymsp[-6].minor.yy427 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy427,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy182,yymsp[0].minor.yy510);
-      if( yymsp[-6].minor.yy427 ){
-        struct SrcList_item *pNew = &yymsp[-6].minor.yy427->a[yymsp[-6].minor.yy427->nSrc-1];
-        struct SrcList_item *pOld = yymsp[-4].minor.yy427->a;
+    if( yymsp[-6].minor.yy135==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy18==0 && yymsp[0].minor.yy48==0 ){
+      yymsp[-6].minor.yy135 = yymsp[-4].minor.yy135;
+    }else if( yymsp[-4].minor.yy135->nSrc==1 ){
+      yymsp[-6].minor.yy135 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy135,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy18,yymsp[0].minor.yy48);
+      if( yymsp[-6].minor.yy135 ){
+        struct SrcList_item *pNew = &yymsp[-6].minor.yy135->a[yymsp[-6].minor.yy135->nSrc-1];
+        struct SrcList_item *pOld = yymsp[-4].minor.yy135->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.yy427);
+      sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy135);
     }else{
       Select *pSubquery;
-      sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy427);
-      pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy427,0,0,0,0,SF_NestedFrom,0);
-      yymsp[-6].minor.yy427 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy427,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy182,yymsp[0].minor.yy510);
+      sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy135);
+      pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy135,0,0,0,0,SF_NestedFrom,0);
+      yymsp[-6].minor.yy135 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy135,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy18,yymsp[0].minor.yy48);
     }
   }
         break;
-      case 107: /* dbnm ::= */
-      case 121: /* indexed_opt ::= */ yytestcase(yyruleno==121);
+      case 108: /* dbnm ::= */
+      case 122: /* indexed_opt ::= */ yytestcase(yyruleno==122);
 {yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;}
         break;
-      case 109: /* fullname ::= nm */
-      case 111: /* xfullname ::= nm */ yytestcase(yyruleno==111);
-{yymsp[0].minor.yy427 = sqlite3SrcListAppend(pParse->db,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/}
+      case 110: /* fullname ::= nm */
+{
+  yylhsminor.yy135 = sqlite3SrcListAppend(pParse->db,0,&yymsp[0].minor.yy0,0);
+  if( IN_RENAME_OBJECT && yylhsminor.yy135 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy135->a[0].zName, &yymsp[0].minor.yy0);
+}
+  yymsp[0].minor.yy135 = yylhsminor.yy135;
+        break;
+      case 111: /* fullname ::= nm DOT nm */
+{
+  yylhsminor.yy135 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
+  if( IN_RENAME_OBJECT && yylhsminor.yy135 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy135->a[0].zName, &yymsp[0].minor.yy0);
+}
+  yymsp[-2].minor.yy135 = yylhsminor.yy135;
+        break;
+      case 112: /* xfullname ::= nm */
+{yymsp[0].minor.yy135 = sqlite3SrcListAppend(pParse->db,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/}
         break;
-      case 110: /* fullname ::= nm DOT nm */
-      case 112: /* xfullname ::= nm DOT nm */ yytestcase(yyruleno==112);
-{yymsp[-2].minor.yy427 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/}
+      case 113: /* xfullname ::= nm DOT nm */
+{yymsp[-2].minor.yy135 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/}
         break;
-      case 113: /* xfullname ::= nm DOT nm AS nm */
+      case 114: /* xfullname ::= nm DOT nm AS nm */
 {
-   yymsp[-4].minor.yy427 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/
-   if( yymsp[-4].minor.yy427 ) yymsp[-4].minor.yy427->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
+   yymsp[-4].minor.yy135 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/
+   if( yymsp[-4].minor.yy135 ) yymsp[-4].minor.yy135->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
 }
         break;
-      case 114: /* xfullname ::= nm AS nm */
+      case 115: /* xfullname ::= nm AS nm */
 {  
-   yymsp[-2].minor.yy427 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/
-   if( yymsp[-2].minor.yy427 ) yymsp[-2].minor.yy427->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
+   yymsp[-2].minor.yy135 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/
+   if( yymsp[-2].minor.yy135 ) yymsp[-2].minor.yy135->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
 }
         break;
-      case 115: /* joinop ::= COMMA|JOIN */
-{ yymsp[0].minor.yy502 = JT_INNER; }
+      case 116: /* joinop ::= COMMA|JOIN */
+{ yymsp[0].minor.yy70 = JT_INNER; }
         break;
-      case 116: /* joinop ::= JOIN_KW JOIN */
-{yymsp[-1].minor.yy502 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0);  /*X-overwrites-A*/}
+      case 117: /* joinop ::= JOIN_KW JOIN */
+{yymsp[-1].minor.yy70 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0);  /*X-overwrites-A*/}
         break;
-      case 117: /* joinop ::= JOIN_KW nm JOIN */
-{yymsp[-2].minor.yy502 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/}
+      case 118: /* joinop ::= JOIN_KW nm JOIN */
+{yymsp[-2].minor.yy70 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/}
         break;
-      case 118: /* joinop ::= JOIN_KW nm nm JOIN */
-{yymsp[-3].minor.yy502 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/}
+      case 119: /* joinop ::= JOIN_KW nm nm JOIN */
+{yymsp[-3].minor.yy70 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/}
         break;
-      case 119: /* on_opt ::= ON expr */
-      case 136: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==136);
-      case 143: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==143);
-      case 208: /* case_else ::= ELSE expr */ yytestcase(yyruleno==208);
-{yymsp[-1].minor.yy182 = yymsp[0].minor.yy182;}
+      case 120: /* on_opt ::= ON expr */
+      case 137: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==137);
+      case 144: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==144);
+      case 210: /* case_else ::= ELSE expr */ yytestcase(yyruleno==210);
+{yymsp[-1].minor.yy18 = yymsp[0].minor.yy18;}
         break;
-      case 120: /* on_opt ::= */
-      case 135: /* having_opt ::= */ yytestcase(yyruleno==135);
-      case 137: /* limit_opt ::= */ yytestcase(yyruleno==137);
-      case 142: /* where_opt ::= */ yytestcase(yyruleno==142);
-      case 209: /* case_else ::= */ yytestcase(yyruleno==209);
-      case 211: /* case_operand ::= */ yytestcase(yyruleno==211);
-{yymsp[1].minor.yy182 = 0;}
+      case 121: /* on_opt ::= */
+      case 136: /* having_opt ::= */ yytestcase(yyruleno==136);
+      case 138: /* limit_opt ::= */ yytestcase(yyruleno==138);
+      case 143: /* where_opt ::= */ yytestcase(yyruleno==143);
+      case 211: /* case_else ::= */ yytestcase(yyruleno==211);
+      case 213: /* case_operand ::= */ yytestcase(yyruleno==213);
+{yymsp[1].minor.yy18 = 0;}
         break;
-      case 122: /* indexed_opt ::= INDEXED BY nm */
+      case 123: /* indexed_opt ::= INDEXED BY nm */
 {yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;}
         break;
-      case 123: /* indexed_opt ::= NOT INDEXED */
+      case 124: /* indexed_opt ::= NOT INDEXED */
 {yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;}
         break;
-      case 124: /* using_opt ::= USING LP idlist RP */
-{yymsp[-3].minor.yy510 = yymsp[-1].minor.yy510;}
+      case 125: /* using_opt ::= USING LP idlist RP */
+{yymsp[-3].minor.yy48 = yymsp[-1].minor.yy48;}
         break;
-      case 125: /* using_opt ::= */
-      case 157: /* idlist_opt ::= */ yytestcase(yyruleno==157);
-{yymsp[1].minor.yy510 = 0;}
+      case 126: /* using_opt ::= */
+      case 158: /* idlist_opt ::= */ yytestcase(yyruleno==158);
+{yymsp[1].minor.yy48 = 0;}
         break;
-      case 127: /* orderby_opt ::= ORDER BY sortlist */
-      case 134: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==134);
-{yymsp[-2].minor.yy232 = yymsp[0].minor.yy232;}
+      case 128: /* orderby_opt ::= ORDER BY sortlist */
+      case 135: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==135);
+{yymsp[-2].minor.yy420 = yymsp[0].minor.yy420;}
         break;
-      case 128: /* sortlist ::= sortlist COMMA expr sortorder */
+      case 129: /* sortlist ::= sortlist COMMA expr sortorder */
 {
-  yymsp[-3].minor.yy232 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy232,yymsp[-1].minor.yy182);
-  sqlite3ExprListSetSortOrder(yymsp[-3].minor.yy232,yymsp[0].minor.yy502);
+  yymsp[-3].minor.yy420 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy420,yymsp[-1].minor.yy18);
+  sqlite3ExprListSetSortOrder(yymsp[-3].minor.yy420,yymsp[0].minor.yy70);
 }
         break;
-      case 129: /* sortlist ::= expr sortorder */
+      case 130: /* sortlist ::= expr sortorder */
 {
-  yymsp[-1].minor.yy232 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy182); /*A-overwrites-Y*/
-  sqlite3ExprListSetSortOrder(yymsp[-1].minor.yy232,yymsp[0].minor.yy502);
+  yymsp[-1].minor.yy420 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy18); /*A-overwrites-Y*/
+  sqlite3ExprListSetSortOrder(yymsp[-1].minor.yy420,yymsp[0].minor.yy70);
 }
         break;
-      case 130: /* sortorder ::= ASC */
-{yymsp[0].minor.yy502 = SQLITE_SO_ASC;}
+      case 131: /* sortorder ::= ASC */
+{yymsp[0].minor.yy70 = SQLITE_SO_ASC;}
         break;
-      case 131: /* sortorder ::= DESC */
-{yymsp[0].minor.yy502 = SQLITE_SO_DESC;}
+      case 132: /* sortorder ::= DESC */
+{yymsp[0].minor.yy70 = SQLITE_SO_DESC;}
         break;
-      case 132: /* sortorder ::= */
-{yymsp[1].minor.yy502 = SQLITE_SO_UNDEFINED;}
+      case 133: /* sortorder ::= */
+{yymsp[1].minor.yy70 = SQLITE_SO_UNDEFINED;}
         break;
-      case 138: /* limit_opt ::= LIMIT expr */
-{yymsp[-1].minor.yy182 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy182,0);}
+      case 139: /* limit_opt ::= LIMIT expr */
+{yymsp[-1].minor.yy18 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy18,0);}
         break;
-      case 139: /* limit_opt ::= LIMIT expr OFFSET expr */
-{yymsp[-3].minor.yy182 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy182,yymsp[0].minor.yy182);}
+      case 140: /* limit_opt ::= LIMIT expr OFFSET expr */
+{yymsp[-3].minor.yy18 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy18,yymsp[0].minor.yy18);}
         break;
-      case 140: /* limit_opt ::= LIMIT expr COMMA expr */
-{yymsp[-3].minor.yy182 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy182,yymsp[-2].minor.yy182);}
+      case 141: /* limit_opt ::= LIMIT expr COMMA expr */
+{yymsp[-3].minor.yy18 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy18,yymsp[-2].minor.yy18);}
         break;
-      case 141: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt */
+      case 142: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt */
 {
-  sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy427, &yymsp[-1].minor.yy0);
-  sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy427,yymsp[0].minor.yy182,0,0);
+  sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy135, &yymsp[-1].minor.yy0);
+  sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy135,yymsp[0].minor.yy18,0,0);
 }
         break;
-      case 144: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */
+      case 145: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */
 {
-  sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy427, &yymsp[-3].minor.yy0);
-  sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy232,"set list"); 
-  sqlite3Update(pParse,yymsp[-4].minor.yy427,yymsp[-1].minor.yy232,yymsp[0].minor.yy182,yymsp[-5].minor.yy502,0,0,0);
+  sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy135, &yymsp[-3].minor.yy0);
+  sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy420,"set list"); 
+  sqlite3Update(pParse,yymsp[-4].minor.yy135,yymsp[-1].minor.yy420,yymsp[0].minor.yy18,yymsp[-5].minor.yy70,0,0,0);
 }
         break;
-      case 145: /* setlist ::= setlist COMMA nm EQ expr */
+      case 146: /* setlist ::= setlist COMMA nm EQ expr */
 {
-  yymsp[-4].minor.yy232 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy232, yymsp[0].minor.yy182);
-  sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy232, &yymsp[-2].minor.yy0, 1);
+  yymsp[-4].minor.yy420 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy420, yymsp[0].minor.yy18);
+  sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy420, &yymsp[-2].minor.yy0, 1);
 }
         break;
-      case 146: /* setlist ::= setlist COMMA LP idlist RP EQ expr */
+      case 147: /* setlist ::= setlist COMMA LP idlist RP EQ expr */
 {
-  yymsp[-6].minor.yy232 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy232, yymsp[-3].minor.yy510, yymsp[0].minor.yy182);
+  yymsp[-6].minor.yy420 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy420, yymsp[-3].minor.yy48, yymsp[0].minor.yy18);
 }
         break;
-      case 147: /* setlist ::= nm EQ expr */
+      case 148: /* setlist ::= nm EQ expr */
 {
-  yylhsminor.yy232 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy182);
-  sqlite3ExprListSetName(pParse, yylhsminor.yy232, &yymsp[-2].minor.yy0, 1);
+  yylhsminor.yy420 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy18);
+  sqlite3ExprListSetName(pParse, yylhsminor.yy420, &yymsp[-2].minor.yy0, 1);
 }
-  yymsp[-2].minor.yy232 = yylhsminor.yy232;
+  yymsp[-2].minor.yy420 = yylhsminor.yy420;
         break;
-      case 148: /* setlist ::= LP idlist RP EQ expr */
+      case 149: /* setlist ::= LP idlist RP EQ expr */
 {
-  yymsp[-4].minor.yy232 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy510, yymsp[0].minor.yy182);
+  yymsp[-4].minor.yy420 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy48, yymsp[0].minor.yy18);
 }
         break;
-      case 149: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
+      case 150: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
 {
-  sqlite3Insert(pParse, yymsp[-3].minor.yy427, yymsp[-1].minor.yy399, yymsp[-2].minor.yy510, yymsp[-5].minor.yy502, yymsp[0].minor.yy198);
+  sqlite3Insert(pParse, yymsp[-3].minor.yy135, yymsp[-1].minor.yy489, yymsp[-2].minor.yy48, yymsp[-5].minor.yy70, yymsp[0].minor.yy340);
 }
         break;
-      case 150: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */
+      case 151: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */
 {
-  sqlite3Insert(pParse, yymsp[-3].minor.yy427, 0, yymsp[-2].minor.yy510, yymsp[-5].minor.yy502, 0);
+  sqlite3Insert(pParse, yymsp[-3].minor.yy135, 0, yymsp[-2].minor.yy48, yymsp[-5].minor.yy70, 0);
 }
         break;
-      case 151: /* upsert ::= */
-{ yymsp[1].minor.yy198 = 0; }
+      case 152: /* upsert ::= */
+{ yymsp[1].minor.yy340 = 0; }
         break;
-      case 152: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */
-{ yymsp[-10].minor.yy198 = sqlite3UpsertNew(pParse->db,yymsp[-7].minor.yy232,yymsp[-5].minor.yy182,yymsp[-1].minor.yy232,yymsp[0].minor.yy182);}
+      case 153: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */
+{ yymsp[-10].minor.yy340 = sqlite3UpsertNew(pParse->db,yymsp[-7].minor.yy420,yymsp[-5].minor.yy18,yymsp[-1].minor.yy420,yymsp[0].minor.yy18);}
         break;
-      case 153: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */
-{ yymsp[-7].minor.yy198 = sqlite3UpsertNew(pParse->db,yymsp[-4].minor.yy232,yymsp[-2].minor.yy182,0,0); }
+      case 154: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */
+{ yymsp[-7].minor.yy340 = sqlite3UpsertNew(pParse->db,yymsp[-4].minor.yy420,yymsp[-2].minor.yy18,0,0); }
         break;
-      case 154: /* upsert ::= ON CONFLICT DO NOTHING */
-{ yymsp[-3].minor.yy198 = sqlite3UpsertNew(pParse->db,0,0,0,0); }
+      case 155: /* upsert ::= ON CONFLICT DO NOTHING */
+{ yymsp[-3].minor.yy340 = sqlite3UpsertNew(pParse->db,0,0,0,0); }
         break;
-      case 158: /* idlist_opt ::= LP idlist RP */
-{yymsp[-2].minor.yy510 = yymsp[-1].minor.yy510;}
+      case 159: /* idlist_opt ::= LP idlist RP */
+{yymsp[-2].minor.yy48 = yymsp[-1].minor.yy48;}
         break;
-      case 159: /* idlist ::= idlist COMMA nm */
-{yymsp[-2].minor.yy510 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy510,&yymsp[0].minor.yy0);}
+      case 160: /* idlist ::= idlist COMMA nm */
+{yymsp[-2].minor.yy48 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy48,&yymsp[0].minor.yy0);}
         break;
-      case 160: /* idlist ::= nm */
-{yymsp[0].minor.yy510 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/}
+      case 161: /* idlist ::= nm */
+{yymsp[0].minor.yy48 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/}
         break;
-      case 161: /* expr ::= LP expr RP */
-{yymsp[-2].minor.yy182 = yymsp[-1].minor.yy182;}
+      case 162: /* expr ::= LP expr RP */
+{yymsp[-2].minor.yy18 = yymsp[-1].minor.yy18;}
         break;
-      case 162: /* expr ::= ID|INDEXED */
-      case 163: /* expr ::= JOIN_KW */ yytestcase(yyruleno==163);
-{yymsp[0].minor.yy182=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
+      case 163: /* expr ::= ID|INDEXED */
+      case 164: /* expr ::= JOIN_KW */ yytestcase(yyruleno==164);
+{yymsp[0].minor.yy18=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
         break;
-      case 164: /* expr ::= nm DOT nm */
+      case 165: /* 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);
-  yylhsminor.yy182 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
+  if( IN_RENAME_OBJECT ){
+    sqlite3RenameTokenMap(pParse, (void*)temp2, &yymsp[0].minor.yy0);
+    sqlite3RenameTokenMap(pParse, (void*)temp1, &yymsp[-2].minor.yy0);
+  }
+  yylhsminor.yy18 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
 }
-  yymsp[-2].minor.yy182 = yylhsminor.yy182;
+  yymsp[-2].minor.yy18 = yylhsminor.yy18;
         break;
-      case 165: /* expr ::= nm DOT nm DOT nm */
+      case 166: /* 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);
-  yylhsminor.yy182 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
+  if( IN_RENAME_OBJECT ){
+    sqlite3RenameTokenMap(pParse, (void*)temp3, &yymsp[0].minor.yy0);
+    sqlite3RenameTokenMap(pParse, (void*)temp2, &yymsp[-2].minor.yy0);
+  }
+  yylhsminor.yy18 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
 }
-  yymsp[-4].minor.yy182 = yylhsminor.yy182;
+  yymsp[-4].minor.yy18 = yylhsminor.yy18;
         break;
-      case 166: /* term ::= NULL|FLOAT|BLOB */
-      case 167: /* term ::= STRING */ yytestcase(yyruleno==167);
-{yymsp[0].minor.yy182=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/}
+      case 167: /* term ::= NULL|FLOAT|BLOB */
+      case 168: /* term ::= STRING */ yytestcase(yyruleno==168);
+{yymsp[0].minor.yy18=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/}
         break;
-      case 168: /* term ::= INTEGER */
+      case 169: /* term ::= INTEGER */
 {
-  yylhsminor.yy182 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
+  yylhsminor.yy18 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
 }
-  yymsp[0].minor.yy182 = yylhsminor.yy182;
+  yymsp[0].minor.yy18 = yylhsminor.yy18;
         break;
-      case 169: /* expr ::= VARIABLE */
+      case 170: /* expr ::= VARIABLE */
 {
   if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){
     u32 n = yymsp[0].minor.yy0.n;
-    yymsp[0].minor.yy182 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0);
-    sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy182, n);
+    yymsp[0].minor.yy18 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0);
+    sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy18, 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
@@ -144622,146 +149322,154 @@ static YYACTIONTYPE yy_reduce(
     assert( t.n>=2 );
     if( pParse->nested==0 ){
       sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t);
-      yymsp[0].minor.yy182 = 0;
+      yymsp[0].minor.yy18 = 0;
     }else{
-      yymsp[0].minor.yy182 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
-      if( yymsp[0].minor.yy182 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy182->iTable);
+      yymsp[0].minor.yy18 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
+      if( yymsp[0].minor.yy18 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy18->iTable);
     }
   }
 }
         break;
-      case 170: /* expr ::= expr COLLATE ID|STRING */
+      case 171: /* expr ::= expr COLLATE ID|STRING */
 {
-  yymsp[-2].minor.yy182 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy182, &yymsp[0].minor.yy0, 1);
+  yymsp[-2].minor.yy18 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy18, &yymsp[0].minor.yy0, 1);
 }
         break;
-      case 171: /* expr ::= CAST LP expr AS typetoken RP */
+      case 172: /* expr ::= CAST LP expr AS typetoken RP */
 {
-  yymsp[-5].minor.yy182 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1);
-  sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy182, yymsp[-3].minor.yy182, 0);
+  yymsp[-5].minor.yy18 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1);
+  sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy18, yymsp[-3].minor.yy18, 0);
 }
         break;
-      case 172: /* expr ::= ID|INDEXED LP distinct exprlist RP */
+      case 173: /* expr ::= ID|INDEXED LP distinct exprlist RP */
 {
-  if( yymsp[-1].minor.yy232 && yymsp[-1].minor.yy232->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
-    sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0);
-  }
-  yylhsminor.yy182 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy232, &yymsp[-4].minor.yy0);
-  if( yymsp[-2].minor.yy502==SF_Distinct && yylhsminor.yy182 ){
-    yylhsminor.yy182->flags |= EP_Distinct;
-  }
+  yylhsminor.yy18 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy420, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy70);
+}
+  yymsp[-4].minor.yy18 = yylhsminor.yy18;
+        break;
+      case 174: /* expr ::= ID|INDEXED LP STAR RP */
+{
+  yylhsminor.yy18 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0);
+}
+  yymsp[-3].minor.yy18 = yylhsminor.yy18;
+        break;
+      case 175: /* expr ::= ID|INDEXED LP distinct exprlist RP over_clause */
+{
+  yylhsminor.yy18 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy420, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy70);
+  sqlite3WindowAttach(pParse, yylhsminor.yy18, yymsp[0].minor.yy327);
 }
-  yymsp[-4].minor.yy182 = yylhsminor.yy182;
+  yymsp[-5].minor.yy18 = yylhsminor.yy18;
         break;
-      case 173: /* expr ::= ID|INDEXED LP STAR RP */
+      case 176: /* expr ::= ID|INDEXED LP STAR RP over_clause */
 {
-  yylhsminor.yy182 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0);
+  yylhsminor.yy18 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0);
+  sqlite3WindowAttach(pParse, yylhsminor.yy18, yymsp[0].minor.yy327);
 }
-  yymsp[-3].minor.yy182 = yylhsminor.yy182;
+  yymsp[-4].minor.yy18 = yylhsminor.yy18;
         break;
-      case 174: /* term ::= CTIME_KW */
+      case 177: /* term ::= CTIME_KW */
 {
-  yylhsminor.yy182 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0);
+  yylhsminor.yy18 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0);
 }
-  yymsp[0].minor.yy182 = yylhsminor.yy182;
+  yymsp[0].minor.yy18 = yylhsminor.yy18;
         break;
-      case 175: /* expr ::= LP nexprlist COMMA expr RP */
+      case 178: /* expr ::= LP nexprlist COMMA expr RP */
 {
-  ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy232, yymsp[-1].minor.yy182);
-  yymsp[-4].minor.yy182 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
-  if( yymsp[-4].minor.yy182 ){
-    yymsp[-4].minor.yy182->x.pList = pList;
+  ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy420, yymsp[-1].minor.yy18);
+  yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
+  if( yymsp[-4].minor.yy18 ){
+    yymsp[-4].minor.yy18->x.pList = pList;
   }else{
     sqlite3ExprListDelete(pParse->db, pList);
   }
 }
         break;
-      case 176: /* expr ::= expr AND expr */
-      case 177: /* expr ::= expr OR expr */ yytestcase(yyruleno==177);
-      case 178: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==178);
-      case 179: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==179);
-      case 180: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==180);
-      case 181: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==181);
-      case 182: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==182);
-      case 183: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==183);
-{yymsp[-2].minor.yy182=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy182,yymsp[0].minor.yy182);}
+      case 179: /* expr ::= expr AND expr */
+      case 180: /* expr ::= expr OR expr */ yytestcase(yyruleno==180);
+      case 181: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==181);
+      case 182: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==182);
+      case 183: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==183);
+      case 184: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==184);
+      case 185: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==185);
+      case 186: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==186);
+{yymsp[-2].minor.yy18=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy18,yymsp[0].minor.yy18);}
         break;
-      case 184: /* likeop ::= NOT LIKE_KW|MATCH */
+      case 187: /* 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 185: /* expr ::= expr likeop expr */
+      case 188: /* 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.yy182);
-  pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy182);
-  yymsp[-2].minor.yy182 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0);
-  if( bNot ) yymsp[-2].minor.yy182 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy182, 0);
-  if( yymsp[-2].minor.yy182 ) yymsp[-2].minor.yy182->flags |= EP_InfixFunc;
+  pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy18);
+  pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy18);
+  yymsp[-2].minor.yy18 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
+  if( bNot ) yymsp[-2].minor.yy18 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy18, 0);
+  if( yymsp[-2].minor.yy18 ) yymsp[-2].minor.yy18->flags |= EP_InfixFunc;
 }
         break;
-      case 186: /* expr ::= expr likeop expr ESCAPE expr */
+      case 189: /* 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.yy182);
-  pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy182);
-  pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy182);
-  yymsp[-4].minor.yy182 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0);
-  if( bNot ) yymsp[-4].minor.yy182 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy182, 0);
-  if( yymsp[-4].minor.yy182 ) yymsp[-4].minor.yy182->flags |= EP_InfixFunc;
+  pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy18);
+  pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy18);
+  pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy18);
+  yymsp[-4].minor.yy18 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0);
+  if( bNot ) yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy18, 0);
+  if( yymsp[-4].minor.yy18 ) yymsp[-4].minor.yy18->flags |= EP_InfixFunc;
 }
         break;
-      case 187: /* expr ::= expr ISNULL|NOTNULL */
-{yymsp[-1].minor.yy182 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy182,0);}
+      case 190: /* expr ::= expr ISNULL|NOTNULL */
+{yymsp[-1].minor.yy18 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy18,0);}
         break;
-      case 188: /* expr ::= expr NOT NULL */
-{yymsp[-2].minor.yy182 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy182,0);}
+      case 191: /* expr ::= expr NOT NULL */
+{yymsp[-2].minor.yy18 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy18,0);}
         break;
-      case 189: /* expr ::= expr IS expr */
+      case 192: /* expr ::= expr IS expr */
 {
-  yymsp[-2].minor.yy182 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy182,yymsp[0].minor.yy182);
-  binaryToUnaryIfNull(pParse, yymsp[0].minor.yy182, yymsp[-2].minor.yy182, TK_ISNULL);
+  yymsp[-2].minor.yy18 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy18,yymsp[0].minor.yy18);
+  binaryToUnaryIfNull(pParse, yymsp[0].minor.yy18, yymsp[-2].minor.yy18, TK_ISNULL);
 }
         break;
-      case 190: /* expr ::= expr IS NOT expr */
+      case 193: /* expr ::= expr IS NOT expr */
 {
-  yymsp[-3].minor.yy182 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy182,yymsp[0].minor.yy182);
-  binaryToUnaryIfNull(pParse, yymsp[0].minor.yy182, yymsp[-3].minor.yy182, TK_NOTNULL);
+  yymsp[-3].minor.yy18 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy18,yymsp[0].minor.yy18);
+  binaryToUnaryIfNull(pParse, yymsp[0].minor.yy18, yymsp[-3].minor.yy18, TK_NOTNULL);
 }
         break;
-      case 191: /* expr ::= NOT expr */
-      case 192: /* expr ::= BITNOT expr */ yytestcase(yyruleno==192);
-{yymsp[-1].minor.yy182 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy182, 0);/*A-overwrites-B*/}
+      case 194: /* expr ::= NOT expr */
+      case 195: /* expr ::= BITNOT expr */ yytestcase(yyruleno==195);
+{yymsp[-1].minor.yy18 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy18, 0);/*A-overwrites-B*/}
         break;
-      case 193: /* expr ::= MINUS expr */
-{yymsp[-1].minor.yy182 = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy182, 0);}
-        break;
-      case 194: /* expr ::= PLUS expr */
-{yymsp[-1].minor.yy182 = sqlite3PExpr(pParse, TK_UPLUS, yymsp[0].minor.yy182, 0);}
+      case 196: /* expr ::= PLUS|MINUS expr */
+{
+  yymsp[-1].minor.yy18 = sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy18, 0);
+  /*A-overwrites-B*/
+}
         break;
-      case 195: /* between_op ::= BETWEEN */
-      case 198: /* in_op ::= IN */ yytestcase(yyruleno==198);
-{yymsp[0].minor.yy502 = 0;}
+      case 197: /* between_op ::= BETWEEN */
+      case 200: /* in_op ::= IN */ yytestcase(yyruleno==200);
+{yymsp[0].minor.yy70 = 0;}
         break;
-      case 197: /* expr ::= expr between_op expr AND expr */
+      case 199: /* expr ::= expr between_op expr AND expr */
 {
-  ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy182);
-  pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy182);
-  yymsp[-4].minor.yy182 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy182, 0);
-  if( yymsp[-4].minor.yy182 ){
-    yymsp[-4].minor.yy182->x.pList = pList;
+  ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy18);
+  pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy18);
+  yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy18, 0);
+  if( yymsp[-4].minor.yy18 ){
+    yymsp[-4].minor.yy18->x.pList = pList;
   }else{
     sqlite3ExprListDelete(pParse->db, pList);
   } 
-  if( yymsp[-3].minor.yy502 ) yymsp[-4].minor.yy182 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy182, 0);
+  if( yymsp[-3].minor.yy70 ) yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy18, 0);
 }
         break;
-      case 200: /* expr ::= expr in_op LP exprlist RP */
+      case 202: /* expr ::= expr in_op LP exprlist RP */
 {
-    if( yymsp[-1].minor.yy232==0 ){
+    if( yymsp[-1].minor.yy420==0 ){
       /* Expressions of the form
       **
       **      expr1 IN ()
@@ -144770,9 +149478,9 @@ static YYACTIONTYPE yy_reduce(
       ** simplify to constants 0 (false) and 1 (true), respectively,
       ** regardless of the value of expr1.
       */
-      sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy182);
-      yymsp[-4].minor.yy182 = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[yymsp[-3].minor.yy502],1);
-    }else if( yymsp[-1].minor.yy232->nExpr==1 ){
+      sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy18);
+      yymsp[-4].minor.yy18 = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[yymsp[-3].minor.yy70],1);
+    }else if( yymsp[-1].minor.yy420->nExpr==1 ){
       /* Expressions of the form:
       **
       **      expr1 IN (?1)
@@ -144789,195 +149497,199 @@ static YYACTIONTYPE yy_reduce(
       ** 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.yy232->a[0].pExpr;
-      yymsp[-1].minor.yy232->a[0].pExpr = 0;
-      sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy232);
+      Expr *pRHS = yymsp[-1].minor.yy420->a[0].pExpr;
+      yymsp[-1].minor.yy420->a[0].pExpr = 0;
+      sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy420);
       /* 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.yy182 = sqlite3PExpr(pParse, yymsp[-3].minor.yy502 ? TK_NE : TK_EQ, yymsp[-4].minor.yy182, pRHS);
+      yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, yymsp[-3].minor.yy70 ? TK_NE : TK_EQ, yymsp[-4].minor.yy18, pRHS);
     }else{
-      yymsp[-4].minor.yy182 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy182, 0);
-      if( yymsp[-4].minor.yy182 ){
-        yymsp[-4].minor.yy182->x.pList = yymsp[-1].minor.yy232;
-        sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy182);
+      yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy18, 0);
+      if( yymsp[-4].minor.yy18 ){
+        yymsp[-4].minor.yy18->x.pList = yymsp[-1].minor.yy420;
+        sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy18);
       }else{
-        sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy232);
+        sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy420);
       }
-      if( yymsp[-3].minor.yy502 ) yymsp[-4].minor.yy182 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy182, 0);
+      if( yymsp[-3].minor.yy70 ) yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy18, 0);
     }
   }
         break;
-      case 201: /* expr ::= LP select RP */
+      case 203: /* expr ::= LP select RP */
 {
-    yymsp[-2].minor.yy182 = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
-    sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy182, yymsp[-1].minor.yy399);
+    yymsp[-2].minor.yy18 = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
+    sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy18, yymsp[-1].minor.yy489);
   }
         break;
-      case 202: /* expr ::= expr in_op LP select RP */
+      case 204: /* expr ::= expr in_op LP select RP */
 {
-    yymsp[-4].minor.yy182 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy182, 0);
-    sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy182, yymsp[-1].minor.yy399);
-    if( yymsp[-3].minor.yy502 ) yymsp[-4].minor.yy182 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy182, 0);
+    yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy18, 0);
+    sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy18, yymsp[-1].minor.yy489);
+    if( yymsp[-3].minor.yy70 ) yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy18, 0);
   }
         break;
-      case 203: /* expr ::= expr in_op nm dbnm paren_exprlist */
+      case 205: /* 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);
-    if( yymsp[0].minor.yy232 )  sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy232);
-    yymsp[-4].minor.yy182 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy182, 0);
-    sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy182, pSelect);
-    if( yymsp[-3].minor.yy502 ) yymsp[-4].minor.yy182 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy182, 0);
+    if( yymsp[0].minor.yy420 )  sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy420);
+    yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy18, 0);
+    sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy18, pSelect);
+    if( yymsp[-3].minor.yy70 ) yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy18, 0);
   }
         break;
-      case 204: /* expr ::= EXISTS LP select RP */
+      case 206: /* expr ::= EXISTS LP select RP */
 {
     Expr *p;
-    p = yymsp[-3].minor.yy182 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
-    sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy399);
+    p = yymsp[-3].minor.yy18 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
+    sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy489);
   }
         break;
-      case 205: /* expr ::= CASE case_operand case_exprlist case_else END */
+      case 207: /* expr ::= CASE case_operand case_exprlist case_else END */
 {
-  yymsp[-4].minor.yy182 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy182, 0);
-  if( yymsp[-4].minor.yy182 ){
-    yymsp[-4].minor.yy182->x.pList = yymsp[-1].minor.yy182 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy232,yymsp[-1].minor.yy182) : yymsp[-2].minor.yy232;
-    sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy182);
+  yymsp[-4].minor.yy18 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy18, 0);
+  if( yymsp[-4].minor.yy18 ){
+    yymsp[-4].minor.yy18->x.pList = yymsp[-1].minor.yy18 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy420,yymsp[-1].minor.yy18) : yymsp[-2].minor.yy420;
+    sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy18);
   }else{
-    sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy232);
-    sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy182);
+    sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy420);
+    sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy18);
   }
 }
         break;
-      case 206: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
+      case 208: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
 {
-  yymsp[-4].minor.yy232 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy232, yymsp[-2].minor.yy182);
-  yymsp[-4].minor.yy232 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy232, yymsp[0].minor.yy182);
+  yymsp[-4].minor.yy420 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy420, yymsp[-2].minor.yy18);
+  yymsp[-4].minor.yy420 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy420, yymsp[0].minor.yy18);
 }
         break;
-      case 207: /* case_exprlist ::= WHEN expr THEN expr */
+      case 209: /* case_exprlist ::= WHEN expr THEN expr */
 {
-  yymsp[-3].minor.yy232 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy182);
-  yymsp[-3].minor.yy232 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy232, yymsp[0].minor.yy182);
+  yymsp[-3].minor.yy420 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy18);
+  yymsp[-3].minor.yy420 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy420, yymsp[0].minor.yy18);
 }
         break;
-      case 210: /* case_operand ::= expr */
-{yymsp[0].minor.yy182 = yymsp[0].minor.yy182; /*A-overwrites-X*/}
+      case 212: /* case_operand ::= expr */
+{yymsp[0].minor.yy18 = yymsp[0].minor.yy18; /*A-overwrites-X*/}
         break;
-      case 213: /* nexprlist ::= nexprlist COMMA expr */
-{yymsp[-2].minor.yy232 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy232,yymsp[0].minor.yy182);}
+      case 215: /* nexprlist ::= nexprlist COMMA expr */
+{yymsp[-2].minor.yy420 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy420,yymsp[0].minor.yy18);}
         break;
-      case 214: /* nexprlist ::= expr */
-{yymsp[0].minor.yy232 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy182); /*A-overwrites-Y*/}
+      case 216: /* nexprlist ::= expr */
+{yymsp[0].minor.yy420 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy18); /*A-overwrites-Y*/}
         break;
-      case 216: /* paren_exprlist ::= LP exprlist RP */
-      case 221: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==221);
-{yymsp[-2].minor.yy232 = yymsp[-1].minor.yy232;}
+      case 218: /* paren_exprlist ::= LP exprlist RP */
+      case 223: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==223);
+{yymsp[-2].minor.yy420 = yymsp[-1].minor.yy420;}
         break;
-      case 217: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
+      case 219: /* 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.yy232, yymsp[-10].minor.yy502,
-                      &yymsp[-11].minor.yy0, yymsp[0].minor.yy182, SQLITE_SO_ASC, yymsp[-8].minor.yy502, SQLITE_IDXTYPE_APPDEF);
+                     sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy420, yymsp[-10].minor.yy70,
+                      &yymsp[-11].minor.yy0, yymsp[0].minor.yy18, SQLITE_SO_ASC, yymsp[-8].minor.yy70, SQLITE_IDXTYPE_APPDEF);
+  if( IN_RENAME_OBJECT && pParse->pNewIndex ){
+    sqlite3RenameTokenMap(pParse, pParse->pNewIndex->zName, &yymsp[-4].minor.yy0);
+  }
 }
         break;
-      case 218: /* uniqueflag ::= UNIQUE */
-      case 258: /* raisetype ::= ABORT */ yytestcase(yyruleno==258);
-{yymsp[0].minor.yy502 = OE_Abort;}
+      case 220: /* uniqueflag ::= UNIQUE */
+      case 260: /* raisetype ::= ABORT */ yytestcase(yyruleno==260);
+{yymsp[0].minor.yy70 = OE_Abort;}
         break;
-      case 219: /* uniqueflag ::= */
-{yymsp[1].minor.yy502 = OE_None;}
+      case 221: /* uniqueflag ::= */
+{yymsp[1].minor.yy70 = OE_None;}
         break;
-      case 222: /* eidlist ::= eidlist COMMA nm collate sortorder */
+      case 224: /* eidlist ::= eidlist COMMA nm collate sortorder */
 {
-  yymsp[-4].minor.yy232 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy232, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy502, yymsp[0].minor.yy502);
+  yymsp[-4].minor.yy420 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy420, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy70, yymsp[0].minor.yy70);
 }
         break;
-      case 223: /* eidlist ::= nm collate sortorder */
+      case 225: /* eidlist ::= nm collate sortorder */
 {
-  yymsp[-2].minor.yy232 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy502, yymsp[0].minor.yy502); /*A-overwrites-Y*/
+  yymsp[-2].minor.yy420 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy70, yymsp[0].minor.yy70); /*A-overwrites-Y*/
 }
         break;
-      case 226: /* cmd ::= DROP INDEX ifexists fullname */
-{sqlite3DropIndex(pParse, yymsp[0].minor.yy427, yymsp[-1].minor.yy502);}
+      case 228: /* cmd ::= DROP INDEX ifexists fullname */
+{sqlite3DropIndex(pParse, yymsp[0].minor.yy135, yymsp[-1].minor.yy70);}
         break;
-      case 227: /* cmd ::= VACUUM */
+      case 229: /* cmd ::= VACUUM */
 {sqlite3Vacuum(pParse,0);}
         break;
-      case 228: /* cmd ::= VACUUM nm */
+      case 230: /* cmd ::= VACUUM nm */
 {sqlite3Vacuum(pParse,&yymsp[0].minor.yy0);}
         break;
-      case 229: /* cmd ::= PRAGMA nm dbnm */
+      case 231: /* cmd ::= PRAGMA nm dbnm */
 {sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);}
         break;
-      case 230: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
+      case 232: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
 {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);}
         break;
-      case 231: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
+      case 233: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
 {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);}
         break;
-      case 232: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
+      case 234: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
 {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);}
         break;
-      case 233: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
+      case 235: /* 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 236: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
+      case 238: /* 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.yy47, &all);
+  sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy207, &all);
 }
         break;
-      case 237: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+      case 239: /* 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.yy502, yymsp[-4].minor.yy300.a, yymsp[-4].minor.yy300.b, yymsp[-2].minor.yy427, yymsp[0].minor.yy182, yymsp[-10].minor.yy502, yymsp[-8].minor.yy502);
+  sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy70, yymsp[-4].minor.yy34.a, yymsp[-4].minor.yy34.b, yymsp[-2].minor.yy135, yymsp[0].minor.yy18, yymsp[-10].minor.yy70, yymsp[-8].minor.yy70);
   yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/
 }
         break;
-      case 238: /* trigger_time ::= BEFORE|AFTER */
-{ yymsp[0].minor.yy502 = yymsp[0].major; /*A-overwrites-X*/ }
+      case 240: /* trigger_time ::= BEFORE|AFTER */
+{ yymsp[0].minor.yy70 = yymsp[0].major; /*A-overwrites-X*/ }
         break;
-      case 239: /* trigger_time ::= INSTEAD OF */
-{ yymsp[-1].minor.yy502 = TK_INSTEAD;}
+      case 241: /* trigger_time ::= INSTEAD OF */
+{ yymsp[-1].minor.yy70 = TK_INSTEAD;}
         break;
-      case 240: /* trigger_time ::= */
-{ yymsp[1].minor.yy502 = TK_BEFORE; }
+      case 242: /* trigger_time ::= */
+{ yymsp[1].minor.yy70 = TK_BEFORE; }
         break;
-      case 241: /* trigger_event ::= DELETE|INSERT */
-      case 242: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==242);
-{yymsp[0].minor.yy300.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy300.b = 0;}
+      case 243: /* trigger_event ::= DELETE|INSERT */
+      case 244: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==244);
+{yymsp[0].minor.yy34.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy34.b = 0;}
         break;
-      case 243: /* trigger_event ::= UPDATE OF idlist */
-{yymsp[-2].minor.yy300.a = TK_UPDATE; yymsp[-2].minor.yy300.b = yymsp[0].minor.yy510;}
+      case 245: /* trigger_event ::= UPDATE OF idlist */
+{yymsp[-2].minor.yy34.a = TK_UPDATE; yymsp[-2].minor.yy34.b = yymsp[0].minor.yy48;}
         break;
-      case 244: /* when_clause ::= */
-      case 263: /* key_opt ::= */ yytestcase(yyruleno==263);
-{ yymsp[1].minor.yy182 = 0; }
+      case 246: /* when_clause ::= */
+      case 265: /* key_opt ::= */ yytestcase(yyruleno==265);
+      case 307: /* filter_opt ::= */ yytestcase(yyruleno==307);
+{ yymsp[1].minor.yy18 = 0; }
         break;
-      case 245: /* when_clause ::= WHEN expr */
-      case 264: /* key_opt ::= KEY expr */ yytestcase(yyruleno==264);
-{ yymsp[-1].minor.yy182 = yymsp[0].minor.yy182; }
+      case 247: /* when_clause ::= WHEN expr */
+      case 266: /* key_opt ::= KEY expr */ yytestcase(yyruleno==266);
+{ yymsp[-1].minor.yy18 = yymsp[0].minor.yy18; }
         break;
-      case 246: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+      case 248: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
 {
-  assert( yymsp[-2].minor.yy47!=0 );
-  yymsp[-2].minor.yy47->pLast->pNext = yymsp[-1].minor.yy47;
-  yymsp[-2].minor.yy47->pLast = yymsp[-1].minor.yy47;
+  assert( yymsp[-2].minor.yy207!=0 );
+  yymsp[-2].minor.yy207->pLast->pNext = yymsp[-1].minor.yy207;
+  yymsp[-2].minor.yy207->pLast = yymsp[-1].minor.yy207;
 }
         break;
-      case 247: /* trigger_cmd_list ::= trigger_cmd SEMI */
+      case 249: /* trigger_cmd_list ::= trigger_cmd SEMI */
 { 
-  assert( yymsp[-1].minor.yy47!=0 );
-  yymsp[-1].minor.yy47->pLast = yymsp[-1].minor.yy47;
+  assert( yymsp[-1].minor.yy207!=0 );
+  yymsp[-1].minor.yy207->pLast = yymsp[-1].minor.yy207;
 }
         break;
-      case 248: /* trnm ::= nm DOT nm */
+      case 250: /* trnm ::= nm DOT nm */
 {
   yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;
   sqlite3ErrorMsg(pParse, 
@@ -144985,196 +149697,306 @@ static YYACTIONTYPE yy_reduce(
         "statements within triggers");
 }
         break;
-      case 249: /* tridxby ::= INDEXED BY nm */
+      case 251: /* tridxby ::= INDEXED BY nm */
 {
   sqlite3ErrorMsg(pParse,
         "the INDEXED BY clause is not allowed on UPDATE or DELETE statements "
         "within triggers");
 }
         break;
-      case 250: /* tridxby ::= NOT INDEXED */
+      case 252: /* tridxby ::= NOT INDEXED */
 {
   sqlite3ErrorMsg(pParse,
         "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements "
         "within triggers");
 }
         break;
-      case 251: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */
-{yylhsminor.yy47 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-5].minor.yy0, yymsp[-2].minor.yy232, yymsp[-1].minor.yy182, yymsp[-6].minor.yy502, yymsp[-7].minor.yy0.z, yymsp[0].minor.yy36);}
-  yymsp[-7].minor.yy47 = yylhsminor.yy47;
+      case 253: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */
+{yylhsminor.yy207 = sqlite3TriggerUpdateStep(pParse, &yymsp[-5].minor.yy0, yymsp[-2].minor.yy420, yymsp[-1].minor.yy18, yymsp[-6].minor.yy70, yymsp[-7].minor.yy0.z, yymsp[0].minor.yy392);}
+  yymsp[-7].minor.yy207 = yylhsminor.yy207;
         break;
-      case 252: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
+      case 254: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
 {
-   yylhsminor.yy47 = sqlite3TriggerInsertStep(pParse->db,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy510,yymsp[-2].minor.yy399,yymsp[-6].minor.yy502,yymsp[-1].minor.yy198,yymsp[-7].minor.yy36,yymsp[0].minor.yy36);/*yylhsminor.yy47-overwrites-yymsp[-6].minor.yy502*/
+   yylhsminor.yy207 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy48,yymsp[-2].minor.yy489,yymsp[-6].minor.yy70,yymsp[-1].minor.yy340,yymsp[-7].minor.yy392,yymsp[0].minor.yy392);/*yylhsminor.yy207-overwrites-yymsp[-6].minor.yy70*/
 }
-  yymsp[-7].minor.yy47 = yylhsminor.yy47;
+  yymsp[-7].minor.yy207 = yylhsminor.yy207;
         break;
-      case 253: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
-{yylhsminor.yy47 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy182, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy36);}
-  yymsp[-5].minor.yy47 = yylhsminor.yy47;
+      case 255: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
+{yylhsminor.yy207 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy18, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy392);}
+  yymsp[-5].minor.yy207 = yylhsminor.yy207;
         break;
-      case 254: /* trigger_cmd ::= scanpt select scanpt */
-{yylhsminor.yy47 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy399, yymsp[-2].minor.yy36, yymsp[0].minor.yy36); /*yylhsminor.yy47-overwrites-yymsp[-1].minor.yy399*/}
-  yymsp[-2].minor.yy47 = yylhsminor.yy47;
+      case 256: /* trigger_cmd ::= scanpt select scanpt */
+{yylhsminor.yy207 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy489, yymsp[-2].minor.yy392, yymsp[0].minor.yy392); /*yylhsminor.yy207-overwrites-yymsp[-1].minor.yy489*/}
+  yymsp[-2].minor.yy207 = yylhsminor.yy207;
         break;
-      case 255: /* expr ::= RAISE LP IGNORE RP */
+      case 257: /* expr ::= RAISE LP IGNORE RP */
 {
-  yymsp[-3].minor.yy182 = sqlite3PExpr(pParse, TK_RAISE, 0, 0); 
-  if( yymsp[-3].minor.yy182 ){
-    yymsp[-3].minor.yy182->affinity = OE_Ignore;
+  yymsp[-3].minor.yy18 = sqlite3PExpr(pParse, TK_RAISE, 0, 0); 
+  if( yymsp[-3].minor.yy18 ){
+    yymsp[-3].minor.yy18->affinity = OE_Ignore;
   }
 }
         break;
-      case 256: /* expr ::= RAISE LP raisetype COMMA nm RP */
+      case 258: /* expr ::= RAISE LP raisetype COMMA nm RP */
 {
-  yymsp[-5].minor.yy182 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1); 
-  if( yymsp[-5].minor.yy182 ) {
-    yymsp[-5].minor.yy182->affinity = (char)yymsp[-3].minor.yy502;
+  yymsp[-5].minor.yy18 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1); 
+  if( yymsp[-5].minor.yy18 ) {
+    yymsp[-5].minor.yy18->affinity = (char)yymsp[-3].minor.yy70;
   }
 }
         break;
-      case 257: /* raisetype ::= ROLLBACK */
-{yymsp[0].minor.yy502 = OE_Rollback;}
+      case 259: /* raisetype ::= ROLLBACK */
+{yymsp[0].minor.yy70 = OE_Rollback;}
         break;
-      case 259: /* raisetype ::= FAIL */
-{yymsp[0].minor.yy502 = OE_Fail;}
+      case 261: /* raisetype ::= FAIL */
+{yymsp[0].minor.yy70 = OE_Fail;}
         break;
-      case 260: /* cmd ::= DROP TRIGGER ifexists fullname */
+      case 262: /* cmd ::= DROP TRIGGER ifexists fullname */
 {
-  sqlite3DropTrigger(pParse,yymsp[0].minor.yy427,yymsp[-1].minor.yy502);
+  sqlite3DropTrigger(pParse,yymsp[0].minor.yy135,yymsp[-1].minor.yy70);
 }
         break;
-      case 261: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+      case 263: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
 {
-  sqlite3Attach(pParse, yymsp[-3].minor.yy182, yymsp[-1].minor.yy182, yymsp[0].minor.yy182);
+  sqlite3Attach(pParse, yymsp[-3].minor.yy18, yymsp[-1].minor.yy18, yymsp[0].minor.yy18);
 }
         break;
-      case 262: /* cmd ::= DETACH database_kw_opt expr */
+      case 264: /* cmd ::= DETACH database_kw_opt expr */
 {
-  sqlite3Detach(pParse, yymsp[0].minor.yy182);
+  sqlite3Detach(pParse, yymsp[0].minor.yy18);
 }
         break;
-      case 265: /* cmd ::= REINDEX */
+      case 267: /* cmd ::= REINDEX */
 {sqlite3Reindex(pParse, 0, 0);}
         break;
-      case 266: /* cmd ::= REINDEX nm dbnm */
+      case 268: /* cmd ::= REINDEX nm dbnm */
 {sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
         break;
-      case 267: /* cmd ::= ANALYZE */
+      case 269: /* cmd ::= ANALYZE */
 {sqlite3Analyze(pParse, 0, 0);}
         break;
-      case 268: /* cmd ::= ANALYZE nm dbnm */
+      case 270: /* cmd ::= ANALYZE nm dbnm */
 {sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
         break;
-      case 269: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
+      case 271: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
 {
-  sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy427,&yymsp[0].minor.yy0);
+  sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy135,&yymsp[0].minor.yy0);
 }
         break;
-      case 270: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
+      case 272: /* 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 271: /* add_column_fullname ::= fullname */
+      case 273: /* add_column_fullname ::= fullname */
 {
   disableLookaside(pParse);
-  sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy427);
+  sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy135);
+}
+        break;
+      case 274: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
+{
+  sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy135, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0);
 }
         break;
-      case 272: /* cmd ::= create_vtab */
+      case 275: /* cmd ::= create_vtab */
 {sqlite3VtabFinishParse(pParse,0);}
         break;
-      case 273: /* cmd ::= create_vtab LP vtabarglist RP */
+      case 276: /* cmd ::= create_vtab LP vtabarglist RP */
 {sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);}
         break;
-      case 274: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
+      case 277: /* 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.yy502);
+    sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy70);
 }
         break;
-      case 275: /* vtabarg ::= */
+      case 278: /* vtabarg ::= */
 {sqlite3VtabArgInit(pParse);}
         break;
-      case 276: /* vtabargtoken ::= ANY */
-      case 277: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==277);
-      case 278: /* lp ::= LP */ yytestcase(yyruleno==278);
+      case 279: /* vtabargtoken ::= ANY */
+      case 280: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==280);
+      case 281: /* lp ::= LP */ yytestcase(yyruleno==281);
 {sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);}
         break;
-      case 279: /* with ::= WITH wqlist */
-      case 280: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==280);
-{ sqlite3WithPush(pParse, yymsp[0].minor.yy91, 1); }
+      case 282: /* with ::= WITH wqlist */
+      case 283: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==283);
+{ sqlite3WithPush(pParse, yymsp[0].minor.yy449, 1); }
+        break;
+      case 284: /* wqlist ::= nm eidlist_opt AS LP select RP */
+{
+  yymsp[-5].minor.yy449 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy420, yymsp[-1].minor.yy489); /*A-overwrites-X*/
+}
+        break;
+      case 285: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
+{
+  yymsp[-7].minor.yy449 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy449, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy420, yymsp[-1].minor.yy489);
+}
+        break;
+      case 286: /* windowdefn_list ::= windowdefn */
+{ yylhsminor.yy327 = yymsp[0].minor.yy327; }
+  yymsp[0].minor.yy327 = yylhsminor.yy327;
+        break;
+      case 287: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */
+{
+  assert( yymsp[0].minor.yy327!=0 );
+  yymsp[0].minor.yy327->pNextWin = yymsp[-2].minor.yy327;
+  yylhsminor.yy327 = yymsp[0].minor.yy327;
+}
+  yymsp[-2].minor.yy327 = yylhsminor.yy327;
+        break;
+      case 288: /* windowdefn ::= nm AS window */
+{
+  if( ALWAYS(yymsp[0].minor.yy327) ){
+    yymsp[0].minor.yy327->zName = sqlite3DbStrNDup(pParse->db, yymsp[-2].minor.yy0.z, yymsp[-2].minor.yy0.n);
+  }
+  yylhsminor.yy327 = yymsp[0].minor.yy327;
+}
+  yymsp[-2].minor.yy327 = yylhsminor.yy327;
+        break;
+      case 289: /* window ::= LP part_opt orderby_opt frame_opt RP */
+{
+  yymsp[-4].minor.yy327 = yymsp[-1].minor.yy327;
+  if( ALWAYS(yymsp[-4].minor.yy327) ){
+    yymsp[-4].minor.yy327->pPartition = yymsp[-3].minor.yy420;
+    yymsp[-4].minor.yy327->pOrderBy = yymsp[-2].minor.yy420;
+  }
+}
+        break;
+      case 290: /* part_opt ::= PARTITION BY nexprlist */
+{ yymsp[-2].minor.yy420 = yymsp[0].minor.yy420; }
+        break;
+      case 291: /* part_opt ::= */
+{ yymsp[1].minor.yy420 = 0; }
+        break;
+      case 292: /* frame_opt ::= */
+{ 
+  yymsp[1].minor.yy327 = sqlite3WindowAlloc(pParse, TK_RANGE, TK_UNBOUNDED, 0, TK_CURRENT, 0);
+}
+        break;
+      case 293: /* frame_opt ::= range_or_rows frame_bound_s */
+{ 
+  yylhsminor.yy327 = sqlite3WindowAlloc(pParse, yymsp[-1].minor.yy70, yymsp[0].minor.yy119.eType, yymsp[0].minor.yy119.pExpr, TK_CURRENT, 0);
+}
+  yymsp[-1].minor.yy327 = yylhsminor.yy327;
+        break;
+      case 294: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e */
+{ 
+  yylhsminor.yy327 = sqlite3WindowAlloc(pParse, yymsp[-4].minor.yy70, yymsp[-2].minor.yy119.eType, yymsp[-2].minor.yy119.pExpr, yymsp[0].minor.yy119.eType, yymsp[0].minor.yy119.pExpr);
+}
+  yymsp[-4].minor.yy327 = yylhsminor.yy327;
+        break;
+      case 295: /* range_or_rows ::= RANGE */
+{ yymsp[0].minor.yy70 = TK_RANGE; }
+        break;
+      case 296: /* range_or_rows ::= ROWS */
+{ yymsp[0].minor.yy70 = TK_ROWS;  }
         break;
-      case 281: /* wqlist ::= nm eidlist_opt AS LP select RP */
+      case 297: /* frame_bound_s ::= frame_bound */
+      case 299: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==299);
+{ yylhsminor.yy119 = yymsp[0].minor.yy119; }
+  yymsp[0].minor.yy119 = yylhsminor.yy119;
+        break;
+      case 298: /* frame_bound_s ::= UNBOUNDED PRECEDING */
+      case 300: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==300);
+{yymsp[-1].minor.yy119.eType = TK_UNBOUNDED; yymsp[-1].minor.yy119.pExpr = 0;}
+        break;
+      case 301: /* frame_bound ::= expr PRECEDING */
+{ yylhsminor.yy119.eType = TK_PRECEDING; yylhsminor.yy119.pExpr = yymsp[-1].minor.yy18; }
+  yymsp[-1].minor.yy119 = yylhsminor.yy119;
+        break;
+      case 302: /* frame_bound ::= CURRENT ROW */
+{ yymsp[-1].minor.yy119.eType = TK_CURRENT  ; yymsp[-1].minor.yy119.pExpr = 0; }
+        break;
+      case 303: /* frame_bound ::= expr FOLLOWING */
+{ yylhsminor.yy119.eType = TK_FOLLOWING; yylhsminor.yy119.pExpr = yymsp[-1].minor.yy18; }
+  yymsp[-1].minor.yy119 = yylhsminor.yy119;
+        break;
+      case 304: /* window_clause ::= WINDOW windowdefn_list */
+{ yymsp[-1].minor.yy327 = yymsp[0].minor.yy327; }
+        break;
+      case 305: /* over_clause ::= filter_opt OVER window */
 {
-  yymsp[-5].minor.yy91 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy232, yymsp[-1].minor.yy399); /*A-overwrites-X*/
+  yylhsminor.yy327 = yymsp[0].minor.yy327;
+  assert( yylhsminor.yy327!=0 );
+  yylhsminor.yy327->pFilter = yymsp[-2].minor.yy18;
 }
+  yymsp[-2].minor.yy327 = yylhsminor.yy327;
         break;
-      case 282: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
+      case 306: /* over_clause ::= filter_opt OVER nm */
 {
-  yymsp[-7].minor.yy91 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy91, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy232, yymsp[-1].minor.yy399);
+  yylhsminor.yy327 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
+  if( yylhsminor.yy327 ){
+    yylhsminor.yy327->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n);
+    yylhsminor.yy327->pFilter = yymsp[-2].minor.yy18;
+  }else{
+    sqlite3ExprDelete(pParse->db, yymsp[-2].minor.yy18);
+  }
 }
+  yymsp[-2].minor.yy327 = yylhsminor.yy327;
+        break;
+      case 308: /* filter_opt ::= FILTER LP WHERE expr RP */
+{ yymsp[-4].minor.yy18 = yymsp[-1].minor.yy18; }
         break;
       default:
-      /* (283) input ::= cmdlist */ yytestcase(yyruleno==283);
-      /* (284) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==284);
-      /* (285) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=285);
-      /* (286) ecmd ::= SEMI */ yytestcase(yyruleno==286);
-      /* (287) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==287);
-      /* (288) ecmd ::= explain cmdx */ yytestcase(yyruleno==288);
-      /* (289) trans_opt ::= */ yytestcase(yyruleno==289);
-      /* (290) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==290);
-      /* (291) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==291);
-      /* (292) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==292);
-      /* (293) savepoint_opt ::= */ yytestcase(yyruleno==293);
-      /* (294) cmd ::= create_table create_table_args */ yytestcase(yyruleno==294);
-      /* (295) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==295);
-      /* (296) columnlist ::= columnname carglist */ yytestcase(yyruleno==296);
-      /* (297) nm ::= ID|INDEXED */ yytestcase(yyruleno==297);
-      /* (298) nm ::= STRING */ yytestcase(yyruleno==298);
-      /* (299) nm ::= JOIN_KW */ yytestcase(yyruleno==299);
-      /* (300) typetoken ::= typename */ yytestcase(yyruleno==300);
-      /* (301) typename ::= ID|STRING */ yytestcase(yyruleno==301);
-      /* (302) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=302);
-      /* (303) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=303);
-      /* (304) carglist ::= carglist ccons */ yytestcase(yyruleno==304);
-      /* (305) carglist ::= */ yytestcase(yyruleno==305);
-      /* (306) ccons ::= NULL onconf */ yytestcase(yyruleno==306);
-      /* (307) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==307);
-      /* (308) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==308);
-      /* (309) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=309);
-      /* (310) tconscomma ::= */ yytestcase(yyruleno==310);
-      /* (311) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=311);
-      /* (312) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=312);
-      /* (313) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=313);
-      /* (314) oneselect ::= values */ yytestcase(yyruleno==314);
-      /* (315) sclp ::= selcollist COMMA */ yytestcase(yyruleno==315);
-      /* (316) as ::= ID|STRING */ yytestcase(yyruleno==316);
-      /* (317) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=317);
-      /* (318) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==318);
-      /* (319) exprlist ::= nexprlist */ yytestcase(yyruleno==319);
-      /* (320) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=320);
-      /* (321) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=321);
-      /* (322) nmnum ::= ON */ yytestcase(yyruleno==322);
-      /* (323) nmnum ::= DELETE */ yytestcase(yyruleno==323);
-      /* (324) nmnum ::= DEFAULT */ yytestcase(yyruleno==324);
-      /* (325) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==325);
-      /* (326) foreach_clause ::= */ yytestcase(yyruleno==326);
-      /* (327) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==327);
-      /* (328) trnm ::= nm */ yytestcase(yyruleno==328);
-      /* (329) tridxby ::= */ yytestcase(yyruleno==329);
-      /* (330) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==330);
-      /* (331) database_kw_opt ::= */ yytestcase(yyruleno==331);
-      /* (332) kwcolumn_opt ::= */ yytestcase(yyruleno==332);
-      /* (333) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==333);
-      /* (334) vtabarglist ::= vtabarg */ yytestcase(yyruleno==334);
-      /* (335) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==335);
-      /* (336) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==336);
-      /* (337) anylist ::= */ yytestcase(yyruleno==337);
-      /* (338) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==338);
-      /* (339) anylist ::= anylist ANY */ yytestcase(yyruleno==339);
-      /* (340) with ::= */ yytestcase(yyruleno==340);
+      /* (309) input ::= cmdlist */ yytestcase(yyruleno==309);
+      /* (310) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==310);
+      /* (311) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=311);
+      /* (312) ecmd ::= SEMI */ yytestcase(yyruleno==312);
+      /* (313) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==313);
+      /* (314) ecmd ::= explain cmdx */ yytestcase(yyruleno==314);
+      /* (315) trans_opt ::= */ yytestcase(yyruleno==315);
+      /* (316) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==316);
+      /* (317) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==317);
+      /* (318) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==318);
+      /* (319) savepoint_opt ::= */ yytestcase(yyruleno==319);
+      /* (320) cmd ::= create_table create_table_args */ yytestcase(yyruleno==320);
+      /* (321) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==321);
+      /* (322) columnlist ::= columnname carglist */ yytestcase(yyruleno==322);
+      /* (323) nm ::= ID|INDEXED */ yytestcase(yyruleno==323);
+      /* (324) nm ::= STRING */ yytestcase(yyruleno==324);
+      /* (325) nm ::= JOIN_KW */ yytestcase(yyruleno==325);
+      /* (326) typetoken ::= typename */ yytestcase(yyruleno==326);
+      /* (327) typename ::= ID|STRING */ yytestcase(yyruleno==327);
+      /* (328) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=328);
+      /* (329) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=329);
+      /* (330) carglist ::= carglist ccons */ yytestcase(yyruleno==330);
+      /* (331) carglist ::= */ yytestcase(yyruleno==331);
+      /* (332) ccons ::= NULL onconf */ yytestcase(yyruleno==332);
+      /* (333) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==333);
+      /* (334) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==334);
+      /* (335) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=335);
+      /* (336) tconscomma ::= */ yytestcase(yyruleno==336);
+      /* (337) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=337);
+      /* (338) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=338);
+      /* (339) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=339);
+      /* (340) oneselect ::= values */ yytestcase(yyruleno==340);
+      /* (341) sclp ::= selcollist COMMA */ yytestcase(yyruleno==341);
+      /* (342) as ::= ID|STRING */ yytestcase(yyruleno==342);
+      /* (343) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=343);
+      /* (344) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==344);
+      /* (345) exprlist ::= nexprlist */ yytestcase(yyruleno==345);
+      /* (346) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=346);
+      /* (347) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=347);
+      /* (348) nmnum ::= ON */ yytestcase(yyruleno==348);
+      /* (349) nmnum ::= DELETE */ yytestcase(yyruleno==349);
+      /* (350) nmnum ::= DEFAULT */ yytestcase(yyruleno==350);
+      /* (351) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==351);
+      /* (352) foreach_clause ::= */ yytestcase(yyruleno==352);
+      /* (353) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==353);
+      /* (354) trnm ::= nm */ yytestcase(yyruleno==354);
+      /* (355) tridxby ::= */ yytestcase(yyruleno==355);
+      /* (356) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==356);
+      /* (357) database_kw_opt ::= */ yytestcase(yyruleno==357);
+      /* (358) kwcolumn_opt ::= */ yytestcase(yyruleno==358);
+      /* (359) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==359);
+      /* (360) vtabarglist ::= vtabarg */ yytestcase(yyruleno==360);
+      /* (361) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==361);
+      /* (362) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==362);
+      /* (363) anylist ::= */ yytestcase(yyruleno==363);
+      /* (364) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==364);
+      /* (365) anylist ::= anylist ANY */ yytestcase(yyruleno==365);
+      /* (366) with ::= */ yytestcase(yyruleno==366);
         break;
 /********** End reduce actions ************************************************/
   };
@@ -145328,12 +150150,12 @@ SQLITE_PRIVATE void sqlite3Parser(
 
   do{
     assert( yyact==yypParser->yytos->stateno );
-    yyact = yy_find_shift_action(yymajor,yyact);
+    yyact = yy_find_shift_action((YYCODETYPE)yymajor,yyact);
     if( yyact >= YY_MIN_REDUCE ){
       yyact = yy_reduce(yypParser,yyact-YY_MIN_REDUCE,yymajor,
                         yyminor sqlite3ParserCTX_PARAM);
     }else if( yyact <= YY_MAX_SHIFTREDUCE ){
-      yy_shift(yypParser,yyact,yymajor,yyminor);
+      yy_shift(yypParser,yyact,(YYCODETYPE)yymajor,yyminor);
 #ifndef YYNOERRORRECOVERY
       yypParser->yyerrcnt--;
 #endif
@@ -145461,6 +150283,21 @@ SQLITE_PRIVATE void sqlite3Parser(
   return;
 }
 
+/*
+** Return the fallback token corresponding to canonical token iToken, or
+** 0 if iToken has no fallback.
+*/
+SQLITE_PRIVATE int sqlite3ParserFallback(int iToken){
+#ifdef YYFALLBACK
+  if( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) ){
+    return yyFallback[iToken];
+  }
+#else
+  (void)iToken;
+#endif
+  return 0;
+}
+
 /************** End of parse.c ***********************************************/
 /************** Begin file tokenize.c ****************************************/
 /*
@@ -145519,11 +150356,12 @@ SQLITE_PRIVATE void sqlite3Parser(
 #define CC_TILDA     25    /* '~' */
 #define CC_DOT       26    /* '.' */
 #define CC_ILLEGAL   27    /* Illegal character */
+#define CC_NUL       28    /* 0x00 */
 
 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,
+/* 0x */   28, 27, 27, 27, 27, 27, 27, 27, 27,  7,  7, 27,  7,  7, 27, 27,
 /* 1x */   27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
 /* 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,
@@ -145622,19 +150460,20 @@ const unsigned char ebcdicToAscii[] = {
 ** is substantially reduced.  This is important for embedded applications
 ** on platforms with limited memory.
 */
-/* Hash score: 185 */
-/* zKWText[] encodes 845 bytes of keyword text in 561 bytes */
+/* Hash score: 208 */
+/* zKWText[] encodes 923 bytes of keyword text in 614 bytes */
 /*   REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT       */
 /*   ABLEFTHENDEFERRABLELSEXCEPTRANSACTIONATURALTERAISEXCLUSIVE         */
 /*   XISTSAVEPOINTERSECTRIGGEREFERENCESCONSTRAINTOFFSETEMPORARY         */
-/*   UNIQUERYWITHOUTERELEASEATTACHAVINGROUPDATEBEGINNERECURSIVE         */
-/*   BETWEENOTHINGLOBYCASCADELETECASECOLLATECREATECURRENT_DATE          */
-/*   DETACHIMMEDIATEJOINSERTLIKEMATCHPLANALYZEPRAGMABORTVALUES          */
-/*   VIRTUALIMITWHENOTNULLWHERENAMEAFTEREPLACEANDEFAULT                 */
-/*   AUTOINCREMENTCASTCOLUMNCOMMITCONFLICTCROSSCURRENT_TIMESTAMP        */
-/*   RIMARYDEFERREDISTINCTDORDERESTRICTDROPFAILFROMFULLIFISNULL         */
-/*   RIGHTROLLBACKROWUNIONUSINGVACUUMVIEWINITIALLY                      */
-static const char zKWText[560] = {
+/*   UNIQUERYWITHOUTERELEASEATTACHAVINGROUPDATEBEGINNERANGEBETWEEN      */
+/*   OTHINGLOBYCASCADELETECASECOLLATECREATECURRENT_DATEDETACH           */
+/*   IMMEDIATEJOINSERTLIKEMATCHPLANALYZEPRAGMABORTVALUESVIRTUALIMIT     */
+/*   WHENOTNULLWHERECURSIVEAFTERENAMEANDEFAULTAUTOINCREMENTCAST         */
+/*   COLUMNCOMMITCONFLICTCROSSCURRENT_TIMESTAMPARTITIONDEFERRED         */
+/*   ISTINCTDROPRECEDINGFAILFILTEREPLACEFOLLOWINGFROMFULLIFISNULL       */
+/*   ORDERESTRICTOVERIGHTROLLBACKROWSUNBOUNDEDUNIONUSINGVACUUMVIEW      */
+/*   INDOWINITIALLYPRIMARY                                              */
+static const char zKWText[613] = {
   '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',
@@ -145647,84 +150486,90 @@ static const char zKWText[560] = {
   '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','H','I','N','G','L','O','B','Y','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','L','I','K','E','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','O','T','N','U','L','L','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','O','R','D','E','R','E','S',
-  'T','R','I','C','T','D','R','O','P','F','A','I','L','F','R','O','M','F',
-  'U','L','L','I','F','I','S','N','U','L','L','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',
+  'T','E','B','E','G','I','N','N','E','R','A','N','G','E','B','E','T','W',
+  'E','E','N','O','T','H','I','N','G','L','O','B','Y','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','L','I','K','E','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','O',
+  'T','N','U','L','L','W','H','E','R','E','C','U','R','S','I','V','E','A',
+  'F','T','E','R','E','N','A','M','E','A','N','D','E','F','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','A','R','T','I','T','I','O','N','D','E','F','E','R',
+  'R','E','D','I','S','T','I','N','C','T','D','R','O','P','R','E','C','E',
+  'D','I','N','G','F','A','I','L','F','I','L','T','E','R','E','P','L','A',
+  'C','E','F','O','L','L','O','W','I','N','G','F','R','O','M','F','U','L',
+  'L','I','F','I','S','N','U','L','L','O','R','D','E','R','E','S','T','R',
+  'I','C','T','O','V','E','R','I','G','H','T','R','O','L','L','B','A','C',
+  'K','R','O','W','S','U','N','B','O','U','N','D','E','D','U','N','I','O',
+  'N','U','S','I','N','G','V','A','C','U','U','M','V','I','E','W','I','N',
+  'D','O','W','I','N','I','T','I','A','L','L','Y','P','R','I','M','A','R',
+  'Y',
 };
 /* aKWHash[i] is the hash value for the i-th keyword */
 static const unsigned char aKWHash[127] = {
-    74, 108, 119,  72,   0,  45,   0,   0,  81,   0,  76,  61,   0,
-    42,  12,  77,  15,   0, 118,  84,  54, 116,   0,  19,   0,   0,
-   123,   0, 121, 111,   0,  22,  96,   0,   9,   0,   0,  68,  69,
-     0,  67,   6,   0,  48,  93, 105,   0, 120, 104,   0,   0,  44,
-     0, 106,  24,   0,  17,   0, 124,  53,  23,   0,   5,  62,  25,
-    99,   0,   0, 126, 112,  60, 125,  57,  28,  55,   0,  94,   0,
-   103,  26,   0, 102,   0,   0,   0,  98,  95, 100,  91, 115,  14,
-    39, 114,   0,  80,   0, 109,  92,  90,  32,   0, 122,  79, 117,
-    86,  46,  83,   0,   0,  97,  40,  59, 110,   0,  36,   0,   0,
-    29,   0,  89,  87,  88,   0,  20,  85,   0,  56,
+    74, 109, 124,  72, 106,  45,   0,   0,  81,   0,  76,  61,   0,
+    42,  12,  77,  15,   0, 123,  84,  54, 118, 125,  19,   0,   0,
+   130,   0, 128, 121,   0,  22,  96,   0,   9,   0,   0, 115,  69,
+     0,  67,   6,   0,  48,  93, 136,   0, 126, 104,   0,   0,  44,
+     0, 107,  24,   0,  17,   0, 131,  53,  23,   0,   5,  62, 132,
+    99,   0,   0, 135, 110,  60, 134,  57, 113,  55,   0,  94,   0,
+   103,  26,   0, 102,   0,   0,   0,  98,  95, 100, 105, 117,  14,
+    39, 116,   0,  80,   0, 133, 114,  92,  59,   0, 129,  79, 119,
+    86,  46,  83,   0,   0,  97,  40, 122, 120,   0, 127,   0,   0,
+    29,   0,  89,  87,  88,   0,  20,  85, 111,  56,
 };
 /* aKWNext[] forms the hash collision chain.  If aKWHash[i]==0
 ** then the i-th keyword has no more hash collisions.  Otherwise,
 ** the next keyword with the same hash is aKWHash[i]-1. */
-static const unsigned char aKWNext[126] = {
+static const unsigned char aKWNext[136] = {
      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,   0,   0,   0,   0,   0,
+     0,  43,   3,  47,   0,   0,  32,   0,   0,   0,   0,   0,   0,
      0,   1,  64,   0,   0,  65,   0,  41,   0,  38,   0,   0,   0,
-     0,   0,  49,  75,   0,   0,  30,   0,  58,   0,   0,  63,  31,
-    52,  16,  34,  10,   0,   0,   0,   0,   0,   0,   0,  11,  70,
-    78,   0,   8,   0,  18,  51,   0, 107, 101,   0, 113,   0,  73,
-    27,  37,  71,  82,   0,  35,  66,   0,   0,
+     0,   0,  49,  75,   0,   0,  30,   0,  58,   0,   0,   0,  31,
+    63,  16,  34,  10,   0,   0,   0,   0,   0,   0,   0,  11,  70,
+    91,   0,   0,   8,   0, 108,   0, 101,  28,  52,  68,   0, 112,
+     0,  73,  51,   0,  90,  27,  37,   0,  71,  36,  82,   0,  35,
+    66,  25,  18,   0,   0,  78,
 };
 /* aKWLen[i] is the length (in bytes) of the i-th keyword */
-static const unsigned char aKWLen[126] = {
+static const unsigned char aKWLen[136] = {
      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,   4,   2,   7,   3,
+     6,   6,   5,   6,   5,   5,   5,   7,   7,   4,   2,   7,   3,
      6,   4,   7,   6,  12,   6,   9,   4,   6,   4,   5,   4,   7,
-     6,   5,   6,   7,   5,   4,   7,   3,   2,   4,   5,   6,   5,
-     7,   3,   7,  13,   2,   2,   4,   6,   6,   8,   5,  17,  12,
-     7,   8,   8,   2,   2,   5,   8,   4,   4,   4,   4,   2,   6,
-     5,   8,   3,   5,   5,   6,   4,   9,   3,
+     6,   5,   6,   7,   5,   4,   7,   3,   2,   4,   5,   9,   5,
+     6,   3,   7,  13,   2,   2,   4,   6,   6,   8,   5,  17,  12,
+     7,   9,   8,   8,   2,   4,   9,   4,   6,   7,   9,   4,   4,
+     2,   6,   5,   8,   4,   5,   8,   4,   3,   9,   5,   5,   6,
+     4,   6,   2,   9,   3,   7,
 };
 /* aKWOffset[i] is the index into zKWText[] of the start of
 ** the text for the i-th keyword. */
-static const unsigned short int aKWOffset[126] = {
+static const unsigned short int aKWOffset[136] = {
      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, 246, 249, 251, 252,
-   256, 262, 266, 273, 279, 291, 297, 306, 308, 314, 318, 323, 325,
-   332, 337, 342, 348, 354, 359, 362, 362, 362, 365, 369, 372, 378,
-   382, 389, 391, 398, 400, 402, 411, 415, 421, 427, 435, 440, 440,
-   456, 463, 470, 471, 478, 479, 483, 491, 495, 499, 503, 507, 509,
-   515, 520, 528, 531, 536, 541, 547, 551, 556,
+   199, 204, 209, 212, 218, 221, 225, 230, 236, 242, 245, 247, 248,
+   252, 258, 262, 269, 275, 287, 293, 302, 304, 310, 314, 319, 321,
+   328, 333, 338, 344, 350, 355, 358, 358, 358, 361, 365, 368, 377,
+   381, 387, 389, 396, 398, 400, 409, 413, 419, 425, 433, 438, 438,
+   438, 454, 463, 470, 471, 478, 481, 490, 494, 499, 506, 515, 519,
+   523, 525, 531, 535, 543, 546, 551, 559, 559, 563, 572, 577, 582,
+   588, 591, 594, 597, 602, 606,
 };
 /* aKWCode[i] is the parser symbol code for the i-th keyword */
-static const unsigned char aKWCode[126] = {
+static const unsigned char aKWCode[136] = {
   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,    
@@ -145736,21 +150581,23 @@ static const unsigned char aKWCode[126] = {
   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_UPDATE,     TK_BEGIN,      TK_JOIN_KW,    TK_RANGE,      TK_BETWEEN,    
   TK_NOTHING,    TK_LIKE_KW,    TK_BY,         TK_CASCADE,    TK_ASC,        
   TK_DELETE,     TK_CASE,       TK_COLLATE,    TK_CREATE,     TK_CTIME_KW,   
   TK_DETACH,     TK_IMMEDIATE,  TK_JOIN,       TK_INSERT,     TK_LIKE_KW,    
   TK_MATCH,      TK_PLAN,       TK_ANALYZE,    TK_PRAGMA,     TK_ABORT,      
   TK_VALUES,     TK_VIRTUAL,    TK_LIMIT,      TK_WHEN,       TK_NOTNULL,    
-  TK_NOT,        TK_NO,         TK_NULL,       TK_WHERE,      TK_RENAME,     
-  TK_AFTER,      TK_REPLACE,    TK_AND,        TK_DEFAULT,    TK_AUTOINCR,   
+  TK_NOT,        TK_NO,         TK_NULL,       TK_WHERE,      TK_RECURSIVE,  
+  TK_AFTER,      TK_RENAME,     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_DO,         TK_ORDER,      
-  TK_RESTRICT,   TK_DROP,       TK_FAIL,       TK_FROM,       TK_JOIN_KW,    
-  TK_IF,         TK_ISNULL,     TK_JOIN_KW,    TK_ROLLBACK,   TK_ROW,        
-  TK_UNION,      TK_USING,      TK_VACUUM,     TK_VIEW,       TK_INITIALLY,  
-  TK_ALL,        
+  TK_CONFLICT,   TK_JOIN_KW,    TK_CTIME_KW,   TK_CTIME_KW,   TK_CURRENT,    
+  TK_PARTITION,  TK_DEFERRED,   TK_DISTINCT,   TK_IS,         TK_DROP,       
+  TK_PRECEDING,  TK_FAIL,       TK_FILTER,     TK_REPLACE,    TK_FOLLOWING,  
+  TK_FROM,       TK_JOIN_KW,    TK_IF,         TK_ISNULL,     TK_ORDER,      
+  TK_RESTRICT,   TK_OVER,       TK_JOIN_KW,    TK_ROLLBACK,   TK_ROWS,       
+  TK_ROW,        TK_UNBOUNDED,  TK_UNION,      TK_USING,      TK_VACUUM,     
+  TK_VIEW,       TK_WINDOW,     TK_DO,         TK_INITIALLY,  TK_ALL,        
+  TK_PRIMARY,    
 };
 /* Check to see if z[0..n-1] is a keyword. If it is, write the
 ** parser symbol code for that keyword into *pType.  Always
@@ -145829,7 +150676,7 @@ static int keywordCode(const char *z, int n, int *pType){
       testcase( i==55 ); /* UPDATE */
       testcase( i==56 ); /* BEGIN */
       testcase( i==57 ); /* INNER */
-      testcase( i==58 ); /* RECURSIVE */
+      testcase( i==58 ); /* RANGE */
       testcase( i==59 ); /* BETWEEN */
       testcase( i==60 ); /* NOTHING */
       testcase( i==61 ); /* GLOB */
@@ -145860,9 +150707,9 @@ static int keywordCode(const char *z, int n, int *pType){
       testcase( i==86 ); /* NO */
       testcase( i==87 ); /* NULL */
       testcase( i==88 ); /* WHERE */
-      testcase( i==89 ); /* RENAME */
+      testcase( i==89 ); /* RECURSIVE */
       testcase( i==90 ); /* AFTER */
-      testcase( i==91 ); /* REPLACE */
+      testcase( i==91 ); /* RENAME */
       testcase( i==92 ); /* AND */
       testcase( i==93 ); /* DEFAULT */
       testcase( i==94 ); /* AUTOINCREMENT */
@@ -145875,28 +150722,38 @@ static int keywordCode(const char *z, int n, int *pType){
       testcase( i==101 ); /* CROSS */
       testcase( i==102 ); /* CURRENT_TIMESTAMP */
       testcase( i==103 ); /* CURRENT_TIME */
-      testcase( i==104 ); /* PRIMARY */
-      testcase( i==105 ); /* DEFERRED */
-      testcase( i==106 ); /* DISTINCT */
-      testcase( i==107 ); /* IS */
-      testcase( i==108 ); /* DO */
-      testcase( i==109 ); /* ORDER */
-      testcase( i==110 ); /* RESTRICT */
-      testcase( i==111 ); /* DROP */
-      testcase( i==112 ); /* FAIL */
-      testcase( i==113 ); /* FROM */
-      testcase( i==114 ); /* FULL */
-      testcase( i==115 ); /* IF */
-      testcase( i==116 ); /* ISNULL */
-      testcase( i==117 ); /* RIGHT */
-      testcase( i==118 ); /* ROLLBACK */
-      testcase( i==119 ); /* ROW */
-      testcase( i==120 ); /* UNION */
-      testcase( i==121 ); /* USING */
-      testcase( i==122 ); /* VACUUM */
-      testcase( i==123 ); /* VIEW */
-      testcase( i==124 ); /* INITIALLY */
-      testcase( i==125 ); /* ALL */
+      testcase( i==104 ); /* CURRENT */
+      testcase( i==105 ); /* PARTITION */
+      testcase( i==106 ); /* DEFERRED */
+      testcase( i==107 ); /* DISTINCT */
+      testcase( i==108 ); /* IS */
+      testcase( i==109 ); /* DROP */
+      testcase( i==110 ); /* PRECEDING */
+      testcase( i==111 ); /* FAIL */
+      testcase( i==112 ); /* FILTER */
+      testcase( i==113 ); /* REPLACE */
+      testcase( i==114 ); /* FOLLOWING */
+      testcase( i==115 ); /* FROM */
+      testcase( i==116 ); /* FULL */
+      testcase( i==117 ); /* IF */
+      testcase( i==118 ); /* ISNULL */
+      testcase( i==119 ); /* ORDER */
+      testcase( i==120 ); /* RESTRICT */
+      testcase( i==121 ); /* OVER */
+      testcase( i==122 ); /* RIGHT */
+      testcase( i==123 ); /* ROLLBACK */
+      testcase( i==124 ); /* ROWS */
+      testcase( i==125 ); /* ROW */
+      testcase( i==126 ); /* UNBOUNDED */
+      testcase( i==127 ); /* UNION */
+      testcase( i==128 ); /* USING */
+      testcase( i==129 ); /* VACUUM */
+      testcase( i==130 ); /* VIEW */
+      testcase( i==131 ); /* WINDOW */
+      testcase( i==132 ); /* DO */
+      testcase( i==133 ); /* INITIALLY */
+      testcase( i==134 ); /* ALL */
+      testcase( i==135 ); /* PRIMARY */
       *pType = aKWCode[i];
       break;
     }
@@ -145908,7 +150765,7 @@ SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char *z, int n){
   keywordCode((char*)z, n, &id);
   return id;
 }
-#define SQLITE_N_KEYWORD 126
+#define SQLITE_N_KEYWORD 136
 SQLITE_API int sqlite3_keyword_name(int i,const char **pzName,int *pnName){
   if( i<0 || i>=SQLITE_N_KEYWORD ) return SQLITE_ERROR;
   *pzName = zKWText + aKWOffset[i];
@@ -145962,11 +150819,85 @@ SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[] = {
 #define IdChar(C)  (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40]))
 #endif
 
-/* Make the IdChar function accessible from ctime.c */
-#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+/* Make the IdChar function accessible from ctime.c and alter.c */
 SQLITE_PRIVATE int sqlite3IsIdChar(u8 c){ return IdChar(c); }
-#endif
 
+#ifndef SQLITE_OMIT_WINDOWFUNC
+/*
+** Return the id of the next token in string (*pz). Before returning, set
+** (*pz) to point to the byte following the parsed token.
+*/
+static int getToken(const unsigned char **pz){
+  const unsigned char *z = *pz;
+  int t;                          /* Token type to return */
+  do {
+    z += sqlite3GetToken(z, &t);
+  }while( t==TK_SPACE );
+  if( t==TK_ID 
+   || t==TK_STRING 
+   || t==TK_JOIN_KW 
+   || t==TK_WINDOW 
+   || t==TK_OVER 
+   || sqlite3ParserFallback(t)==TK_ID 
+  ){
+    t = TK_ID;
+  }
+  *pz = z;
+  return t;
+}
+
+/*
+** The following three functions are called immediately after the tokenizer
+** reads the keywords WINDOW, OVER and FILTER, respectively, to determine
+** whether the token should be treated as a keyword or an SQL identifier.
+** This cannot be handled by the usual lemon %fallback method, due to
+** the ambiguity in some constructions. e.g.
+**
+**   SELECT sum(x) OVER ...
+**
+** In the above, "OVER" might be a keyword, or it might be an alias for the 
+** sum(x) expression. If a "%fallback ID OVER" directive were added to 
+** grammar, then SQLite would always treat "OVER" as an alias, making it
+** impossible to call a window-function without a FILTER clause.
+**
+** WINDOW is treated as a keyword if:
+**
+**   * the following token is an identifier, or a keyword that can fallback
+**     to being an identifier, and
+**   * the token after than one is TK_AS.
+**
+** OVER is a keyword if:
+**
+**   * the previous token was TK_RP, and
+**   * the next token is either TK_LP or an identifier.
+**
+** FILTER is a keyword if:
+**
+**   * the previous token was TK_RP, and
+**   * the next token is TK_LP.
+*/
+static int analyzeWindowKeyword(const unsigned char *z){
+  int t;
+  t = getToken(&z);
+  if( t!=TK_ID ) return TK_ID;
+  t = getToken(&z);
+  if( t!=TK_AS ) return TK_ID;
+  return TK_WINDOW;
+}
+static int analyzeOverKeyword(const unsigned char *z, int lastToken){
+  if( lastToken==TK_RP ){
+    int t = getToken(&z);
+    if( t==TK_LP || t==TK_ID ) return TK_OVER;
+  }
+  return TK_ID;
+}
+static int analyzeFilterKeyword(const unsigned char *z, int lastToken){
+  if( lastToken==TK_RP && getToken(&z)==TK_LP ){
+    return TK_FILTER;
+  }
+  return TK_ID;
+}
+#endif /* SQLITE_OMIT_WINDOWFUNC */
 
 /*
 ** Return the length (in bytes) of the token that begins at z[0]. 
@@ -146235,6 +151166,10 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
       i = 1;
       break;
     }
+    case CC_NUL: {
+      *tokenType = TK_ILLEGAL;
+      return 0;
+    }
     default: {
       *tokenType = TK_ILLEGAL;
       return 1;
@@ -146288,47 +151223,64 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
   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;
-      }
-      n = 0;
+    n = sqlite3GetToken((u8*)zSql, &tokenType);
+    mxSqlLen -= n;
+    if( mxSqlLen<0 ){
+      pParse->rc = SQLITE_TOOBIG;
+      break;
     }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+    if( tokenType>=TK_WINDOW ){
+      assert( tokenType==TK_SPACE || tokenType==TK_OVER || tokenType==TK_FILTER
+           || tokenType==TK_ILLEGAL || tokenType==TK_WINDOW 
+      );
+#else
     if( tokenType>=TK_SPACE ){
       assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL );
+#endif /* SQLITE_OMIT_WINDOWFUNC */
       if( db->u1.isInterrupted ){
         pParse->rc = SQLITE_INTERRUPT;
         break;
       }
-      if( tokenType==TK_ILLEGAL ){
+      if( tokenType==TK_SPACE ){
+        zSql += n;
+        continue;
+      }
+      if( zSql[0]==0 ){
+        /* 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;
+        }
+        n = 0;
+#ifndef SQLITE_OMIT_WINDOWFUNC
+      }else if( tokenType==TK_WINDOW ){
+        assert( n==6 );
+        tokenType = analyzeWindowKeyword((const u8*)&zSql[6]);
+      }else if( tokenType==TK_OVER ){
+        assert( n==4 );
+        tokenType = analyzeOverKeyword((const u8*)&zSql[4], lastTokenParsed);
+      }else if( tokenType==TK_FILTER ){
+        assert( n==6 );
+        tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed);
+#endif /* SQLITE_OMIT_WINDOWFUNC */
+      }else{
         sqlite3ErrorMsg(pParse, "unrecognized token: \"%.*s\"", n, zSql);
         break;
       }
-      zSql += n;
-    }else{
-      pParse->sLastToken.z = zSql;
-      pParse->sLastToken.n = n;
-      sqlite3Parser(pEngine, tokenType, pParse->sLastToken);
-      lastTokenParsed = tokenType;
-      zSql += n;
-      if( pParse->rc!=SQLITE_OK || db->mallocFailed ) break;
     }
+    pParse->sLastToken.z = zSql;
+    pParse->sLastToken.n = n;
+    sqlite3Parser(pEngine, tokenType, pParse->sLastToken);
+    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,
@@ -146350,10 +151302,12 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
   assert( pzErrMsg!=0 );
   if( pParse->zErrMsg ){
     *pzErrMsg = pParse->zErrMsg;
-    sqlite3_log(pParse->rc, "%s", *pzErrMsg);
+    sqlite3_log(pParse->rc, "%s in \"%s\"", 
+                *pzErrMsg, pParse->zTail);
     pParse->zErrMsg = 0;
     nErr++;
   }
+  pParse->zTail = zSql;
   if( pParse->pVdbe && pParse->nErr>0 && pParse->nested==0 ){
     sqlite3VdbeDelete(pParse->pVdbe);
     pParse->pVdbe = 0;
@@ -146369,16 +151323,18 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
   sqlite3_free(pParse->apVtabLock);
 #endif
 
-  if( !IN_DECLARE_VTAB ){
+  if( !IN_SPECIAL_PARSE ){
     /* If the pParse->declareVtab flag is set, do not delete any table 
     ** structure built up in pParse->pNewTable. The calling code (see vtab.c)
     ** will take responsibility for freeing the Table structure.
     */
     sqlite3DeleteTable(db, pParse->pNewTable);
   }
+  if( !IN_RENAME_OBJECT ){
+    sqlite3DeleteTrigger(db, pParse->pNewTrigger);
+  }
 
   if( pParse->pWithToFree ) sqlite3WithDelete(db, pParse->pWithToFree);
-  sqlite3DeleteTrigger(db, pParse->pNewTrigger);
   sqlite3DbFree(db, pParse->pVList);
   while( pParse->pAinc ){
     AutoincInfo *p = pParse->pAinc;
@@ -147635,7 +152591,7 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
             db->flags &= ~aFlagOp[i].mask;
           }
           if( oldFlags!=db->flags ){
-            sqlite3ExpirePreparedStatements(db);
+            sqlite3ExpirePreparedStatements(db, 0);
           }
           if( pRes ){
             *pRes = (db->flags & aFlagOp[i].mask)!=0;
@@ -147696,6 +152652,15 @@ static int binCollFunc(
   return rc;
 }
 
+/*
+** Return true if CollSeq is the default built-in BINARY.
+*/
+SQLITE_PRIVATE int sqlite3IsBinary(const CollSeq *p){
+  assert( p==0 || p->xCmp!=binCollFunc || p->pUser!=0
+            || strcmp(p->zName,"BINARY")==0 );
+  return p==0 || (p->xCmp==binCollFunc && p->pUser==0);
+}
+
 /*
 ** Another built-in collating sequence: NOCASE. 
 **
@@ -147817,7 +152782,7 @@ static void disconnectAllVtab(sqlite3 *db){
   sqlite3BtreeEnterAll(db);
   for(i=0; i<db->nDb; i++){
     Schema *pSchema = db->aDb[i].pSchema;
-    if( db->aDb[i].pSchema ){
+    if( pSchema ){
       for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
         Table *pTab = (Table *)sqliteHashData(p);
         if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab);
@@ -148077,8 +153042,8 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
   sqlite3VtabRollback(db);
   sqlite3EndBenignMalloc();
 
-  if( (db->mDbFlags&DBFLAG_SchemaChange)!=0 && db->init.busy==0 ){
-    sqlite3ExpirePreparedStatements(db);
+  if( schemaChange ){
+    sqlite3ExpirePreparedStatements(db, 0);
     sqlite3ResetAllSchemasOfConnection(db);
   }
   sqlite3BtreeLeaveAll(db);
@@ -148106,6 +153071,7 @@ SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
     switch( rc ){
       case SQLITE_OK:                 zName = "SQLITE_OK";                break;
       case SQLITE_ERROR:              zName = "SQLITE_ERROR";             break;
+      case SQLITE_ERROR_SNAPSHOT:     zName = "SQLITE_ERROR_SNAPSHOT";    break;
       case SQLITE_INTERNAL:           zName = "SQLITE_INTERNAL";          break;
       case SQLITE_PERM:               zName = "SQLITE_PERM";              break;
       case SQLITE_ABORT:              zName = "SQLITE_ABORT";             break;
@@ -148469,6 +153435,8 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
   void (*xSFunc)(sqlite3_context*,int,sqlite3_value **),
   void (*xStep)(sqlite3_context*,int,sqlite3_value **),
   void (*xFinal)(sqlite3_context*),
+  void (*xValue)(sqlite3_context*),
+  void (*xInverse)(sqlite3_context*,int,sqlite3_value **),
   FuncDestructor *pDestructor
 ){
   FuncDef *p;
@@ -148476,12 +153444,14 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
   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))) ){
+  assert( xValue==0 || xSFunc==0 );
+  if( zFunctionName==0                /* Must have a valid name */
+   || (xSFunc!=0 && xFinal!=0)        /* Not both xSFunc and xFinal */
+   || ((xFinal==0)!=(xStep==0))       /* Both or neither of xFinal and xStep */
+   || ((xValue==0)!=(xInverse==0))    /* Both or neither of xValue, xInverse */
+   || (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG)
+   || (255<(nName = sqlite3Strlen30( zFunctionName)))
+  ){
     return SQLITE_MISUSE_BKPT;
   }
 
@@ -148502,10 +153472,10 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
   }else if( enc==SQLITE_ANY ){
     int rc;
     rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8|extraFlags,
-         pUserData, xSFunc, xStep, xFinal, pDestructor);
+         pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
     if( rc==SQLITE_OK ){
       rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE|extraFlags,
-          pUserData, xSFunc, xStep, xFinal, pDestructor);
+          pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
     }
     if( rc!=SQLITE_OK ){
       return rc;
@@ -148522,14 +153492,14 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
   ** 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( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==(u32)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);
+      sqlite3ExpirePreparedStatements(db, 0);
     }
   }
 
@@ -148551,38 +153521,32 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
   testcase( p->funcFlags & SQLITE_DETERMINISTIC );
   p->xSFunc = xSFunc ? xSFunc : xStep;
   p->xFinalize = xFinal;
+  p->xValue = xValue;
+  p->xInverse = xInverse;
   p->pUserData = pUserData;
   p->nArg = (u16)nArg;
   return SQLITE_OK;
 }
 
 /*
-** Create new user functions.
+** Worker function used by utf-8 APIs that create new functions:
+**
+**    sqlite3_create_function()
+**    sqlite3_create_function_v2()
+**    sqlite3_create_window_function()
 */
-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(
+static int createFunctionApi(
   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 (*xSFunc)(sqlite3_context*,int,sqlite3_value**),
+  void (*xStep)(sqlite3_context*,int,sqlite3_value**),
   void (*xFinal)(sqlite3_context*),
-  void (*xDestroy)(void *)
+  void (*xValue)(sqlite3_context*),
+  void (*xInverse)(sqlite3_context*,int,sqlite3_value**),
+  void(*xDestroy)(void*)
 ){
   int rc = SQLITE_ERROR;
   FuncDestructor *pArg = 0;
@@ -148604,7 +153568,9 @@ SQLITE_API int sqlite3_create_function_v2(
     pArg->xDestroy = xDestroy;
     pArg->pUserData = p;
   }
-  rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xSFunc, xStep, xFinal, pArg);
+  rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, 
+      xSFunc, xStep, xFinal, xValue, xInverse, pArg
+  );
   if( pArg && pArg->nRef==0 ){
     assert( rc!=SQLITE_OK );
     xDestroy(p);
@@ -148617,6 +153583,52 @@ SQLITE_API int sqlite3_create_function_v2(
   return rc;
 }
 
+/*
+** 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 createFunctionApi(db, zFunc, nArg, enc, p, xSFunc, xStep,
+                                    xFinal, 0, 0, 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 *)
+){
+  return createFunctionApi(db, zFunc, nArg, enc, p, xSFunc, xStep,
+                                    xFinal, 0, 0, xDestroy);
+}
+SQLITE_API int sqlite3_create_window_function(
+  sqlite3 *db,
+  const char *zFunc,
+  int nArg,
+  int enc,
+  void *p,
+  void (*xStep)(sqlite3_context*,int,sqlite3_value **),
+  void (*xFinal)(sqlite3_context*),
+  void (*xValue)(sqlite3_context*),
+  void (*xInverse)(sqlite3_context*,int,sqlite3_value **),
+  void (*xDestroy)(void *)
+){
+  return createFunctionApi(db, zFunc, nArg, enc, p, 0, xStep,
+                                    xFinal, xValue, xInverse, xDestroy);
+}
+
 #ifndef SQLITE_OMIT_UTF16
 SQLITE_API int sqlite3_create_function16(
   sqlite3 *db,
@@ -148637,7 +153649,7 @@ SQLITE_API int sqlite3_create_function16(
   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);
+  rc = sqlite3CreateFunc(db, zFunc8, nArg, eTextRep, p, xSFunc,xStep,xFinal,0,0,0);
   sqlite3DbFree(db, zFunc8);
   rc = sqlite3ApiExit(db, rc);
   sqlite3_mutex_leave(db->mutex);
@@ -149262,7 +154274,7 @@ static int createCollation(
         "unable to delete/modify collation sequence due to active statements");
       return SQLITE_BUSY;
     }
-    sqlite3ExpirePreparedStatements(db);
+    sqlite3ExpirePreparedStatements(db, 0);
 
     /* If collation sequence pColl was created directly by a call to
     ** sqlite3_create_collation, and not generated by synthCollSeq(),
@@ -150451,6 +155463,9 @@ SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, vo
     }else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){
       *(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager);
       rc = SQLITE_OK;
+    }else if( op==SQLITE_FCNTL_DATA_VERSION ){
+      *(unsigned int*)pArg = sqlite3PagerDataVersion(pPager);
+      rc = SQLITE_OK;
     }else{
       rc = sqlite3OsFileControl(fd, op, pArg);
     }
@@ -150714,7 +155729,8 @@ SQLITE_API int sqlite3_test_control(int op, ...){
     */
     case SQLITE_TESTCTRL_VDBE_COVERAGE: {
 #ifdef SQLITE_VDBE_COVERAGE
-      typedef void (*branch_callback)(void*,int,u8,u8);
+      typedef void (*branch_callback)(void*,unsigned int,
+                                      unsigned char,unsigned char);
       sqlite3GlobalConfig.xVdbeBranch = va_arg(ap,branch_callback);
       sqlite3GlobalConfig.pVdbeBranchArg = va_arg(ap,void*);
 #endif
@@ -150901,7 +155917,7 @@ SQLITE_API int sqlite3_snapshot_get(
     if( iDb==0 || iDb>1 ){
       Btree *pBt = db->aDb[iDb].pBt;
       if( 0==sqlite3BtreeIsInTrans(pBt) ){
-        rc = sqlite3BtreeBeginTrans(pBt, 0);
+        rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
         if( rc==SQLITE_OK ){
           rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot);
         }
@@ -150936,11 +155952,29 @@ SQLITE_API int sqlite3_snapshot_open(
     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( sqlite3BtreeIsInTrans(pBt)==0 ){
+        Pager *pPager = sqlite3BtreePager(pBt);
+        int bUnlock = 0;
+        if( sqlite3BtreeIsInReadTrans(pBt) ){
+          if( db->nVdbeActive==0 ){
+            rc = sqlite3PagerSnapshotCheck(pPager, pSnapshot);
+            if( rc==SQLITE_OK ){
+              bUnlock = 1;
+              rc = sqlite3BtreeCommit(pBt);
+            }
+          }
+        }else{
+          rc = SQLITE_OK;
+        }
         if( rc==SQLITE_OK ){
-          rc = sqlite3BtreeBeginTrans(pBt, 0);
-          sqlite3PagerSnapshotOpen(sqlite3BtreePager(pBt), 0);
+          rc = sqlite3PagerSnapshotOpen(pPager, pSnapshot);
+        }
+        if( rc==SQLITE_OK ){
+          rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
+          sqlite3PagerSnapshotOpen(pPager, 0);
+        }
+        if( bUnlock ){
+          sqlite3PagerSnapshotUnlock(pPager);
         }
       }
     }
@@ -150971,7 +156005,7 @@ SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){
   if( iDb==0 || iDb>1 ){
     Btree *pBt = db->aDb[iDb].pBt;
     if( 0==sqlite3BtreeIsInReadTrans(pBt) ){
-      rc = sqlite3BtreeBeginTrans(pBt, 0);
+      rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
       if( rc==SQLITE_OK ){
         rc = sqlite3PagerSnapshotRecover(sqlite3BtreePager(pBt));
         sqlite3BtreeCommit(pBt);
@@ -156094,7 +161128,7 @@ static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
   int rc = SQLITE_OK;
   UNUSED_PARAMETER(iSavepoint);
   assert( ((Fts3Table *)pVtab)->inTransaction );
-  assert( ((Fts3Table *)pVtab)->mxSavepoint < iSavepoint );
+  assert( ((Fts3Table *)pVtab)->mxSavepoint <= iSavepoint );
   TESTONLY( ((Fts3Table *)pVtab)->mxSavepoint = iSavepoint );
   if( ((Fts3Table *)pVtab)->bIgnoreSavepoint==0 ){
     rc = fts3SyncMethod(pVtab);
@@ -170517,9 +175551,9 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
 #endif /* !defined(SQLITE_DISABLE_FTS3_UNICODE) */
 
 /************** End of fts3_unicode2.c ***************************************/
-/************** Begin file rtree.c *******************************************/
+/************** Begin file json1.c *******************************************/
 /*
-** 2001 September 15
+** 2015-08-12
 **
 ** The author disclaims copyright to this source code.  In place of
 ** a legal notice, here is a blessing:
@@ -170528,19641 +175562,21408 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int bRemoveDiacritic){
 **    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.  If the r-tree contains auxiliary columns, those are stored
-** on the end of the %_rowid table.
-**
-** 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.
+** This SQLite extension implements JSON functions.  The interface is
+** modeled after MySQL JSON functions:
 **
-**   2. The next 2 bytes contain the number of entries currently 
-**      stored in the node.
+**     https://dev.mysql.com/doc/refman/5.7/en/json.html
 **
-**   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.
+** For the time being, all JSON is stored as pure text.  (We might add
+** a JSONB type in the future which stores a binary encoding of JSON in
+** a BLOB, but there is no support for JSONB in the current implementation.
+** This implementation parses JSON text at 250 MB/s, so it is hard to see
+** how JSONB might improve on that.)
 */
-
-#if !defined(SQLITE_CORE) \
-  || (defined(SQLITE_ENABLE_RTREE) && !defined(SQLITE_OMIT_VIRTUALTABLE))
-
-#ifndef SQLITE_CORE
-/*   #include "sqlite3ext.h" */
-  SQLITE_EXTENSION_INIT1
-#else
-/*   #include "sqlite3.h" */
+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1)
+#if !defined(SQLITEINT_H)
+/* #include "sqlite3ext.h" */
 #endif
-
-/* #include <string.h> */
+SQLITE_EXTENSION_INIT1
 /* #include <assert.h> */
-/* #include <stdio.h> */
+/* #include <string.h> */
+/* #include <stdlib.h> */
+/* #include <stdarg.h> */
 
-#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;
+/* Mark a function parameter as unused, to suppress nuisance compiler
+** warnings. */
+#ifndef UNUSED_PARAM
+# define UNUSED_PARAM(X)  (void)(X)
 #endif
 
-/*  The following macro is used to suppress compiler warnings.
-*/
-#ifndef UNUSED_PARAMETER
-# define UNUSED_PARAMETER(x) (void)(x)
+#ifndef LARGEST_INT64
+# define LARGEST_INT64  (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
+# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
 #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
-
-/* Maximum number of auxiliary columns */
-#define RTREE_MAX_AUX_COLUMN 100
-
-/* Size of hash table Rtree.aHash. This hash table is not expected to
-** ever contain very many entries, so a fixed number of buckets is 
-** 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 */
-  u8 nAux;                    /* # of auxiliary columns in %_rowid */
-  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 */
-  u32 nNodeRef;               /* Number RtreeNodes with positive nRef */
-  char *zReadAuxSql;          /* SQL for statement to read aux data */
-
-  /* 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;
-
-  /* Statement for writing to the "aux:" fields, if there are any */
-  sqlite3_stmt *pWriteAux;
-
-  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.
+** Versions of isspace(), isalnum() and isdigit() to which it is safe
+** to pass signed char values.
 */
-#ifdef SQLITE_RTREE_INT_ONLY
-  typedef sqlite3_int64 RtreeDValue;       /* High accuracy coordinate */
-  typedef int RtreeValue;                  /* Low accuracy coordinate */
-# define RTREE_ZERO 0
+#ifdef sqlite3Isdigit
+   /* Use the SQLite core versions if this routine is part of the
+   ** SQLite amalgamation */
+#  define safe_isdigit(x)  sqlite3Isdigit(x)
+#  define safe_isalnum(x)  sqlite3Isalnum(x)
+#  define safe_isxdigit(x) sqlite3Isxdigit(x)
 #else
-  typedef double RtreeDValue;              /* High accuracy coordinate */
-  typedef float RtreeValue;                /* Low accuracy coordinate */
-# define RTREE_ZERO 0.0
+   /* Use the standard library for separate compilation */
+#include <ctype.h>  /* amalgamator: keep */
+#  define safe_isdigit(x)  isdigit((unsigned char)(x))
+#  define safe_isalnum(x)  isalnum((unsigned char)(x))
+#  define safe_isxdigit(x) isxdigit((unsigned char)(x))
 #endif
 
 /*
-** 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.
+** Growing our own isspace() routine this way is twice as fast as
+** the library isspace() function, resulting in a 7% overall performance
+** increase for the parser.  (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
 */
-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 */
+static const char jsonIsSpace[] = {
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 1, 1, 0, 0, 1, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  1, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
 };
+#define safe_isspace(x) (jsonIsSpace[(unsigned char)x])
 
-/*
-** 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 
-** 3^40 is greater than 2^64, an r-tree structure always has a depth of
-** 40 or less.
-*/
-#define RTREE_MAX_DEPTH 40
-
+#ifndef SQLITE_AMALGAMATION
+  /* Unsigned integer types.  These are already defined in the sqliteInt.h,
+  ** but the definitions need to be repeated for separate compilation. */
+  typedef sqlite3_uint64 u64;
+  typedef unsigned int u32;
+  typedef unsigned short int u16;
+  typedef unsigned char u8;
+#endif
 
-/*
-** 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
+/* Objects */
+typedef struct JsonString JsonString;
+typedef struct JsonNode JsonNode;
+typedef struct JsonParse JsonParse;
 
-/* 
-** An rtree cursor object.
+/* An instance of this object represents a JSON string
+** under construction.  Really, this is a generic string accumulator
+** that can be and is used to create strings other than JSON.
 */
-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 */
-  u8 bAuxValid;                     /* True if pReadAux 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 */
-  sqlite3_stmt *pReadAux;           /* Statement to read aux-data */
-  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 */
+struct JsonString {
+  sqlite3_context *pCtx;   /* Function context - put error messages here */
+  char *zBuf;              /* Append JSON content here */
+  u64 nAlloc;              /* Bytes of storage available in zBuf[] */
+  u64 nUsed;               /* Bytes of zBuf[] currently used */
+  u8 bStatic;              /* True if zBuf is static space */
+  u8 bErr;                 /* True if an error has been encountered */
+  char zSpace[100];        /* Initial static space */
 };
 
-/* 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.
+/* JSON type values
 */
-union RtreeCoord {
-  RtreeValue f;      /* Floating point value */
-  int i;             /* Integer value */
-  u32 u;             /* Unsigned for byte-order conversions */
-};
+#define JSON_NULL     0
+#define JSON_TRUE     1
+#define JSON_FALSE    2
+#define JSON_INT      3
+#define JSON_REAL     4
+#define JSON_STRING   5
+#define JSON_ARRAY    6
+#define JSON_OBJECT   7
 
-/*
-** 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
+/* The "subtype" set for JSON values */
+#define JSON_SUBTYPE  74    /* Ascii for "J" */
 
 /*
-** 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.
+** Names of the various JSON types:
 */
-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 */
+static const char * const jsonType[] = {
+  "null", "true", "false", "integer", "real", "text", "array", "object"
 };
 
-/* Return the number of cells in a node  */
-#define NCELL(pNode) readInt16(&(pNode)->zData[2])
-
-/* 
-** A single cell from a node, deserialized
+/* Bit values for the JsonNode.jnFlag field
 */
-struct RtreeCell {
-  i64 iRowid;                                 /* Node or entry ID */
-  RtreeCoord aCoord[RTREE_MAX_DIMENSIONS*2];  /* Bounding box coordinates */
-};
+#define JNODE_RAW     0x01         /* Content is raw, not JSON encoded */
+#define JNODE_ESCAPE  0x02         /* Content is text with \ escapes */
+#define JNODE_REMOVE  0x04         /* Do not output */
+#define JNODE_REPLACE 0x08         /* Replace with JsonNode.u.iReplace */
+#define JNODE_PATCH   0x10         /* Patch with JsonNode.u.pPatch */
+#define JNODE_APPEND  0x20         /* More ARRAY/OBJECT entries at u.iAppend */
+#define JNODE_LABEL   0x40         /* Is a label of an object */
 
 
-/*
-** 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().
+/* A single node of parsed JSON
 */
-struct RtreeGeomCallback {
-  int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*);
-  int (*xQueryFunc)(sqlite3_rtree_query_info*);
-  void (*xDestructor)(void*);
-  void *pContext;
+struct JsonNode {
+  u8 eType;              /* One of the JSON_ type values */
+  u8 jnFlags;            /* JNODE flags */
+  u32 n;                 /* Bytes of content, or number of sub-nodes */
+  union {
+    const char *zJContent; /* Content for INT, REAL, and STRING */
+    u32 iAppend;           /* More terms for ARRAY and OBJECT */
+    u32 iKey;              /* Key for ARRAY objects in json_tree() */
+    u32 iReplace;          /* Replacement content for JNODE_REPLACE */
+    JsonNode *pPatch;      /* Node chain of patch for JNODE_PATCH */
+  } u;
 };
 
-/*
-** 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.
+/* A completely parsed JSON string
 */
-struct RtreeMatchArg {
-  u32 iSize;                  /* Size of this object */
-  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 */
+struct JsonParse {
+  u32 nNode;         /* Number of slots of aNode[] used */
+  u32 nAlloc;        /* Number of slots of aNode[] allocated */
+  JsonNode *aNode;   /* Array of nodes containing the parse */
+  const char *zJson; /* Original JSON string */
+  u32 *aUp;          /* Index of parent of each node */
+  u8 oom;            /* Set to true if out of memory */
+  u8 nErr;           /* Number of errors seen */
+  u16 iDepth;        /* Nesting depth */
+  int nJson;         /* Length of the zJson string in bytes */
+  u32 iHold;         /* Replace cache line with the lowest iHold value */
 };
 
-#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.
+** Maximum nesting depth of JSON for this implementation.
 **
-** 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.
+** This limit is needed to avoid a stack overflow in the recursive
+** descent parser.  A depth of 2000 is far deeper than any sane JSON
+** should go.
 */
-#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
-
+#define JSON_MAX_DEPTH  2000
 
-/* 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
+/**************************************************************************
+** Utility routines for dealing with JsonString objects
+**************************************************************************/
 
-/*
-** Functions to deserialize a 16 bit integer, 32 bit real number and
-** 64 bit integer. The deserialized value is returned.
+/* Set the JsonString object to an empty string
 */
-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
+static void jsonZero(JsonString *p){
+  p->zBuf = p->zSpace;
+  p->nAlloc = sizeof(p->zSpace);
+  p->nUsed = 0;
+  p->bStatic = 1;
 }
 
-/*
-** 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).
+/* Initialize the JsonString object
 */
-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;
+static void jsonInit(JsonString *p, sqlite3_context *pCtx){
+  p->pCtx = pCtx;
+  p->bErr = 0;
+  jsonZero(p);
 }
 
-/*
-** Increment the reference count of node p.
+
+/* Free all allocated memory and reset the JsonString object back to its
+** initial state.
 */
-static void nodeReference(RtreeNode *p){
-  if( p ){
-    assert( p->nRef>0 );
-    p->nRef++;
-  }
+static void jsonReset(JsonString *p){
+  if( !p->bStatic ) sqlite3_free(p->zBuf);
+  jsonZero(p);
 }
 
-/*
-** Clear the content of node p (set all bytes to 0x00).
+
+/* Report an out-of-memory (OOM) condition 
 */
-static void nodeZero(Rtree *pRtree, RtreeNode *p){
-  memset(&p->zData[2], 0, pRtree->iNodeSize-2);
-  p->isDirty = 1;
+static void jsonOom(JsonString *p){
+  p->bErr = 1;
+  sqlite3_result_error_nomem(p->pCtx);
+  jsonReset(p);
 }
 
-/*
-** Given a node number iNode, return the corresponding key to use
-** in the Rtree.aHash table.
+/* Enlarge pJson->zBuf so that it can hold at least N more bytes.
+** Return zero on success.  Return non-zero on an OOM error
 */
-static int nodeHash(i64 iNode){
-  return iNode % HASHSIZE;
+static int jsonGrow(JsonString *p, u32 N){
+  u64 nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10;
+  char *zNew;
+  if( p->bStatic ){
+    if( p->bErr ) return 1;
+    zNew = sqlite3_malloc64(nTotal);
+    if( zNew==0 ){
+      jsonOom(p);
+      return SQLITE_NOMEM;
+    }
+    memcpy(zNew, p->zBuf, (size_t)p->nUsed);
+    p->zBuf = zNew;
+    p->bStatic = 0;
+  }else{
+    zNew = sqlite3_realloc64(p->zBuf, nTotal);
+    if( zNew==0 ){
+      jsonOom(p);
+      return SQLITE_NOMEM;
+    }
+    p->zBuf = zNew;
+  }
+  p->nAlloc = nTotal;
+  return SQLITE_OK;
 }
 
-/*
-** Search the node hash table for node iNode. If found, return a pointer
-** to it. Otherwise, return 0.
+/* Append N bytes from zIn onto the end of the JsonString string.
 */
-static RtreeNode *nodeHashLookup(Rtree *pRtree, i64 iNode){
-  RtreeNode *p;
-  for(p=pRtree->aHash[nodeHash(iNode)]; p && p->iNode!=iNode; p=p->pNext);
-  return p;
+static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
+  if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return;
+  memcpy(p->zBuf+p->nUsed, zIn, N);
+  p->nUsed += N;
 }
 
-/*
-** Add node pNode to the node hash table.
+/* Append formatted text (not to exceed N bytes) to the JsonString.
 */
-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;
+static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
+  va_list ap;
+  if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return;
+  va_start(ap, zFormat);
+  sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap);
+  va_end(ap);
+  p->nUsed += (int)strlen(p->zBuf+p->nUsed);
 }
 
-/*
-** Remove node pNode from the node hash table.
+/* Append a single character
 */
-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;
-  }
+static void jsonAppendChar(JsonString *p, char c){
+  if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return;
+  p->zBuf[p->nUsed++] = c;
 }
 
-/*
-** 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.
+/* Append a comma separator to the output buffer, if the previous
+** character is not '[' or '{'.
 */
-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;
-    pRtree->nNodeRef++;
-    pNode->pParent = pParent;
-    pNode->isDirty = 1;
-    nodeReference(pParent);
-  }
-  return pNode;
+static void jsonAppendSeparator(JsonString *p){
+  char c;
+  if( p->nUsed==0 ) return;
+  c = p->zBuf[p->nUsed-1];
+  if( c!='[' && c!='{' ) jsonAppendChar(p, ',');
 }
 
-/*
-** Clear the Rtree.pNodeBlob object
+/* Append the N-byte string in zIn to the end of the JsonString string
+** under construction.  Enclose the string in "..." and escape
+** any double-quotes or backslash characters contained within the
+** string.
 */
-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);
+static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
+  u32 i;
+  if( (N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0 ) return;
+  p->zBuf[p->nUsed++] = '"';
+  for(i=0; i<N; i++){
+    unsigned char c = ((unsigned const char*)zIn)[i];
+    if( c=='"' || c=='\\' ){
+      json_simple_escape:
+      if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return;
+      p->zBuf[p->nUsed++] = '\\';
+    }else if( c<=0x1f ){
+      static const char aSpecial[] = {
+         0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0,
+         0, 0, 0, 0, 0, 0, 0, 0,   0,   0,   0, 0,   0,   0, 0, 0
+      };
+      assert( sizeof(aSpecial)==32 );
+      assert( aSpecial['\b']=='b' );
+      assert( aSpecial['\f']=='f' );
+      assert( aSpecial['\n']=='n' );
+      assert( aSpecial['\r']=='r' );
+      assert( aSpecial['\t']=='t' );
+      if( aSpecial[c] ){
+        c = aSpecial[c];
+        goto json_simple_escape;
+      }
+      if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return;
+      p->zBuf[p->nUsed++] = '\\';
+      p->zBuf[p->nUsed++] = 'u';
+      p->zBuf[p->nUsed++] = '0';
+      p->zBuf[p->nUsed++] = '0';
+      p->zBuf[p->nUsed++] = '0' + (c>>4);
+      c = "0123456789abcdef"[c&0xf];
+    }
+    p->zBuf[p->nUsed++] = c;
   }
+  p->zBuf[p->nUsed++] = '"';
+  assert( p->nUsed<p->nAlloc );
 }
 
 /*
-** Obtain a reference to an r-tree node.
+** Append a function parameter value to the JSON string under 
+** construction.
 */
-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 */
+static void jsonAppendValue(
+  JsonString *p,                 /* Append to this JSON string */
+  sqlite3_value *pValue          /* Value to append */
 ){
-  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))!=0 ){
-    assert( !pParent || !pNode->pParent || pNode->pParent==pParent );
-    if( pParent && !pNode->pParent ){
-      pParent->nRef++;
-      pNode->pParent = pParent;
+  switch( sqlite3_value_type(pValue) ){
+    case SQLITE_NULL: {
+      jsonAppendRaw(p, "null", 4);
+      break;
     }
-    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;
+    case SQLITE_INTEGER:
+    case SQLITE_FLOAT: {
+      const char *z = (const char*)sqlite3_value_text(pValue);
+      u32 n = (u32)sqlite3_value_bytes(pValue);
+      jsonAppendRaw(p, z, n);
+      break;
     }
-  }
-  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;
-      pRtree->nNodeRef++;
-      pNode->iNode = iNode;
-      pNode->isDirty = 0;
-      pNode->pNext = 0;
-      rc = sqlite3_blob_read(pRtree->pNodeBlob, pNode->zData,
-                             pRtree->iNodeSize, 0);
-      nodeReference(pParent);
+    case SQLITE_TEXT: {
+      const char *z = (const char*)sqlite3_value_text(pValue);
+      u32 n = (u32)sqlite3_value_bytes(pValue);
+      if( sqlite3_value_subtype(pValue)==JSON_SUBTYPE ){
+        jsonAppendRaw(p, z, n);
+      }else{
+        jsonAppendString(p, z, n);
+      }
+      break;
     }
-  }
-
-  /* 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;
+    default: {
+      if( p->bErr==0 ){
+        sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1);
+        p->bErr = 2;
+        jsonReset(p);
+      }
+      break;
     }
   }
+}
 
-  /* 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{
-    if( pNode ){
-      pRtree->nNodeRef--;
-      sqlite3_free(pNode);
-    }
-    *ppNode = 0;
+/* Make the JSON in p the result of the SQL function.
+*/
+static void jsonResult(JsonString *p){
+  if( p->bErr==0 ){
+    sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, 
+                          p->bStatic ? SQLITE_TRANSIENT : sqlite3_free,
+                          SQLITE_UTF8);
+    jsonZero(p);
   }
-
-  return rc;
+  assert( p->bStatic );
 }
 
+/**************************************************************************
+** Utility routines for dealing with JsonNode and JsonParse objects
+**************************************************************************/
+
 /*
-** Overwrite cell iCell of node pNode with the contents of pCell.
+** Return the number of consecutive JsonNode slots need to represent
+** the parsed JSON at pNode.  The minimum answer is 1.  For ARRAY and
+** OBJECT types, the number might be larger.
+**
+** Appended elements are not counted.  The value returned is the number
+** by which the JsonNode counter should increment in order to go to the
+** next peer value.
 */
-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; ii<pRtree->nDim2; ii++){
-    p += writeCoord(p, &pCell->aCoord[ii]);
-  }
-  pNode->isDirty = 1;
+static u32 jsonNodeSize(JsonNode *pNode){
+  return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1;
 }
 
 /*
-** Remove the cell with index iCell from node pNode.
+** Reclaim all memory allocated by a JsonParse object.  But do not
+** delete the JsonParse object itself.
 */
-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;
+static void jsonParseReset(JsonParse *pParse){
+  sqlite3_free(pParse->aNode);
+  pParse->aNode = 0;
+  pParse->nNode = 0;
+  pParse->nAlloc = 0;
+  sqlite3_free(pParse->aUp);
+  pParse->aUp = 0;
 }
 
 /*
-** 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.
+** Free a JsonParse object that was obtained from sqlite3_malloc().
 */
-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( nCell<nMaxCell ){
-    nodeOverwriteCell(pRtree, pNode, pCell, nCell);
-    writeInt16(&pNode->zData[2], nCell+1);
-    pNode->isDirty = 1;
-  }
-
-  return (nCell==nMaxCell);
+static void jsonParseFree(JsonParse *pParse){
+  jsonParseReset(pParse);
+  sqlite3_free(pParse);
 }
 
 /*
-** If the node is dirty, write it out to the database.
+** Convert the JsonNode pNode into a pure JSON string and
+** append to pOut.  Subsubstructure is also included.  Return
+** the number of JsonNode objects that are encoded.
 */
-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);
-    sqlite3_bind_null(p, 2);
-    if( pNode->iNode==0 && rc==SQLITE_OK ){
-      pNode->iNode = sqlite3_last_insert_rowid(pRtree->db);
-      nodeHashInsert(pRtree, pNode);
+static void jsonRenderNode(
+  JsonNode *pNode,               /* The node to render */
+  JsonString *pOut,              /* Write JSON here */
+  sqlite3_value **aReplace       /* Replacement values */
+){
+  if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){
+    if( pNode->jnFlags & JNODE_REPLACE ){
+      jsonAppendValue(pOut, aReplace[pNode->u.iReplace]);
+      return;
     }
+    pNode = pNode->u.pPatch;
   }
-  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 );
-    assert( pRtree->nNodeRef>0 );
-    pNode->nRef--;
-    if( pNode->nRef==0 ){
-      pRtree->nNodeRef--;
-      if( pNode->iNode==1 ){
-        pRtree->iDepth = -1;
+  switch( pNode->eType ){
+    default: {
+      assert( pNode->eType==JSON_NULL );
+      jsonAppendRaw(pOut, "null", 4);
+      break;
+    }
+    case JSON_TRUE: {
+      jsonAppendRaw(pOut, "true", 4);
+      break;
+    }
+    case JSON_FALSE: {
+      jsonAppendRaw(pOut, "false", 5);
+      break;
+    }
+    case JSON_STRING: {
+      if( pNode->jnFlags & JNODE_RAW ){
+        jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
+        break;
       }
-      if( pNode->pParent ){
-        rc = nodeRelease(pRtree, pNode->pParent);
+      /* Fall through into the next case */
+    }
+    case JSON_REAL:
+    case JSON_INT: {
+      jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
+      break;
+    }
+    case JSON_ARRAY: {
+      u32 j = 1;
+      jsonAppendChar(pOut, '[');
+      for(;;){
+        while( j<=pNode->n ){
+          if( (pNode[j].jnFlags & JNODE_REMOVE)==0 ){
+            jsonAppendSeparator(pOut);
+            jsonRenderNode(&pNode[j], pOut, aReplace);
+          }
+          j += jsonNodeSize(&pNode[j]);
+        }
+        if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
+        pNode = &pNode[pNode->u.iAppend];
+        j = 1;
       }
-      if( rc==SQLITE_OK ){
-        rc = nodeWrite(pRtree, pNode);
+      jsonAppendChar(pOut, ']');
+      break;
+    }
+    case JSON_OBJECT: {
+      u32 j = 1;
+      jsonAppendChar(pOut, '{');
+      for(;;){
+        while( j<=pNode->n ){
+          if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){
+            jsonAppendSeparator(pOut);
+            jsonRenderNode(&pNode[j], pOut, aReplace);
+            jsonAppendChar(pOut, ':');
+            jsonRenderNode(&pNode[j+1], pOut, aReplace);
+          }
+          j += 1 + jsonNodeSize(&pNode[j+1]);
+        }
+        if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
+        pNode = &pNode[pNode->u.iAppend];
+        j = 1;
       }
-      nodeHashDelete(pRtree, pNode);
-      sqlite3_free(pNode);
+      jsonAppendChar(pOut, '}');
+      break;
     }
   }
-  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.
+** Return a JsonNode and all its descendents as a JSON string.
 */
-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 */
+static void jsonReturnJson(
+  JsonNode *pNode,            /* Node to return */
+  sqlite3_context *pCtx,      /* Return value for this function */
+  sqlite3_value **aReplace    /* Array of replacement values */
 ){
-  assert( iCell<NCELL(pNode) );
-  return readInt64(&pNode->zData[4 + pRtree->nBytesPerCell*iCell]);
+  JsonString s;
+  jsonInit(&s, pCtx);
+  jsonRenderNode(pNode, &s, aReplace);
+  jsonResult(&s);
+  sqlite3_result_subtype(pCtx, JSON_SUBTYPE);
 }
 
 /*
-** Return coordinate iCoord from cell iCell in node pNode.
+** Make the JsonNode the return value of the function.
 */
-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 */
+static void jsonReturn(
+  JsonNode *pNode,            /* Node to return */
+  sqlite3_context *pCtx,      /* Return value for this function */
+  sqlite3_value **aReplace    /* Array of replacement values */
 ){
-  readCoord(&pNode->zData[12 + pRtree->nBytesPerCell*iCell + 4*iCoord], pCoord);
+  switch( pNode->eType ){
+    default: {
+      assert( pNode->eType==JSON_NULL );
+      sqlite3_result_null(pCtx);
+      break;
+    }
+    case JSON_TRUE: {
+      sqlite3_result_int(pCtx, 1);
+      break;
+    }
+    case JSON_FALSE: {
+      sqlite3_result_int(pCtx, 0);
+      break;
+    }
+    case JSON_INT: {
+      sqlite3_int64 i = 0;
+      const char *z = pNode->u.zJContent;
+      if( z[0]=='-' ){ z++; }
+      while( z[0]>='0' && z[0]<='9' ){
+        unsigned v = *(z++) - '0';
+        if( i>=LARGEST_INT64/10 ){
+          if( i>LARGEST_INT64/10 ) goto int_as_real;
+          if( z[0]>='0' && z[0]<='9' ) goto int_as_real;
+          if( v==9 ) goto int_as_real;
+          if( v==8 ){
+            if( pNode->u.zJContent[0]=='-' ){
+              sqlite3_result_int64(pCtx, SMALLEST_INT64);
+              goto int_done;
+            }else{
+              goto int_as_real;
+            }
+          }
+        }
+        i = i*10 + v;
+      }
+      if( pNode->u.zJContent[0]=='-' ){ i = -i; }
+      sqlite3_result_int64(pCtx, i);
+      int_done:
+      break;
+      int_as_real: /* fall through to real */;
+    }
+    case JSON_REAL: {
+      double r;
+#ifdef SQLITE_AMALGAMATION
+      const char *z = pNode->u.zJContent;
+      sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
+#else
+      r = strtod(pNode->u.zJContent, 0);
+#endif
+      sqlite3_result_double(pCtx, r);
+      break;
+    }
+    case JSON_STRING: {
+#if 0 /* Never happens because JNODE_RAW is only set by json_set(),
+      ** json_insert() and json_replace() and those routines do not
+      ** call jsonReturn() */
+      if( pNode->jnFlags & JNODE_RAW ){
+        sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n,
+                            SQLITE_TRANSIENT);
+      }else 
+#endif
+      assert( (pNode->jnFlags & JNODE_RAW)==0 );
+      if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){
+        /* JSON formatted without any backslash-escapes */
+        sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2,
+                            SQLITE_TRANSIENT);
+      }else{
+        /* Translate JSON formatted string into raw text */
+        u32 i;
+        u32 n = pNode->n;
+        const char *z = pNode->u.zJContent;
+        char *zOut;
+        u32 j;
+        zOut = sqlite3_malloc( n+1 );
+        if( zOut==0 ){
+          sqlite3_result_error_nomem(pCtx);
+          break;
+        }
+        for(i=1, j=0; i<n-1; i++){
+          char c = z[i];
+          if( c!='\\' ){
+            zOut[j++] = c;
+          }else{
+            c = z[++i];
+            if( c=='u' ){
+              u32 v = 0, k;
+              for(k=0; k<4; i++, k++){
+                assert( i<n-2 );
+                c = z[i+1];
+                assert( safe_isxdigit(c) );
+                if( c<='9' ) v = v*16 + c - '0';
+                else if( c<='F' ) v = v*16 + c - 'A' + 10;
+                else v = v*16 + c - 'a' + 10;
+              }
+              if( v==0 ) break;
+              if( v<=0x7f ){
+                zOut[j++] = (char)v;
+              }else if( v<=0x7ff ){
+                zOut[j++] = (char)(0xc0 | (v>>6));
+                zOut[j++] = 0x80 | (v&0x3f);
+              }else{
+                zOut[j++] = (char)(0xe0 | (v>>12));
+                zOut[j++] = 0x80 | ((v>>6)&0x3f);
+                zOut[j++] = 0x80 | (v&0x3f);
+              }
+            }else{
+              if( c=='b' ){
+                c = '\b';
+              }else if( c=='f' ){
+                c = '\f';
+              }else if( c=='n' ){
+                c = '\n';
+              }else if( c=='r' ){
+                c = '\r';
+              }else if( c=='t' ){
+                c = '\t';
+              }
+              zOut[j++] = c;
+            }
+          }
+        }
+        zOut[j] = 0;
+        sqlite3_result_text(pCtx, zOut, j, sqlite3_free);
+      }
+      break;
+    }
+    case JSON_ARRAY:
+    case JSON_OBJECT: {
+      jsonReturnJson(pNode, pCtx, aReplace);
+      break;
+    }
+  }
 }
 
+/* Forward reference */
+static int jsonParseAddNode(JsonParse*,u32,u32,const char*);
+
 /*
-** Deserialize cell iCell of node pNode. Populate the structure pointed
-** to by pCell with the results.
+** A macro to hint to the compiler that a function should not be
+** inlined.
 */
-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( ii<pRtree->nDim2 );
-}
-
+#if defined(__GNUC__)
+#  define JSON_NOINLINE  __attribute__((noinline))
+#elif defined(_MSC_VER) && _MSC_VER>=1310
+#  define JSON_NOINLINE  __declspec(noinline)
+#else
+#  define JSON_NOINLINE
+#endif
 
-/* 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
+static JSON_NOINLINE int jsonParseAddNodeExpand(
+  JsonParse *pParse,        /* Append the node to this object */
+  u32 eType,                /* Node type */
+  u32 n,                    /* Content size or sub-node count */
+  const char *zContent      /* Content */
 ){
-  return rtreeInit(db, pAux, argc, argv, ppVtab, pzErr, 1);
+  u32 nNew;
+  JsonNode *pNew;
+  assert( pParse->nNode>=pParse->nAlloc );
+  if( pParse->oom ) return -1;
+  nNew = pParse->nAlloc*2 + 10;
+  pNew = sqlite3_realloc(pParse->aNode, sizeof(JsonNode)*nNew);
+  if( pNew==0 ){
+    pParse->oom = 1;
+    return -1;
+  }
+  pParse->nAlloc = nNew;
+  pParse->aNode = pNew;
+  assert( pParse->nNode<pParse->nAlloc );
+  return jsonParseAddNode(pParse, eType, n, zContent);
 }
 
-/* 
-** Rtree virtual table module xConnect method.
+/*
+** Create a new JsonNode instance based on the arguments and append that
+** instance to the JsonParse.  Return the index in pParse->aNode[] of the
+** new node, or -1 if a memory allocation fails.
 */
-static int rtreeConnect(
-  sqlite3 *db,
-  void *pAux,
-  int argc, const char *const*argv,
-  sqlite3_vtab **ppVtab,
-  char **pzErr
+static int jsonParseAddNode(
+  JsonParse *pParse,        /* Append the node to this object */
+  u32 eType,                /* Node type */
+  u32 n,                    /* Content size or sub-node count */
+  const char *zContent      /* Content */
 ){
-  return rtreeInit(db, pAux, argc, argv, ppVtab, pzErr, 0);
+  JsonNode *p;
+  if( pParse->nNode>=pParse->nAlloc ){
+    return jsonParseAddNodeExpand(pParse, eType, n, zContent);
+  }
+  p = &pParse->aNode[pParse->nNode];
+  p->eType = (u8)eType;
+  p->jnFlags = 0;
+  p->n = n;
+  p->u.zJContent = zContent;
+  return pParse->nNode++;
 }
 
 /*
-** Increment the r-tree reference count.
+** Return true if z[] begins with 4 (or more) hexadecimal digits
 */
-static void rtreeReference(Rtree *pRtree){
-  pRtree->nBusy++;
+static int jsonIs4Hex(const char *z){
+  int i;
+  for(i=0; i<4; i++) if( !safe_isxdigit(z[i]) ) return 0;
+  return 1;
 }
 
 /*
-** Decrement the r-tree reference count. When the reference count reaches
-** zero the structure is deleted.
+** Parse a single JSON value which begins at pParse->zJson[i].  Return the
+** index of the first character past the end of the value parsed.
+**
+** Return negative for a syntax error.  Special cases:  return -2 if the
+** first non-whitespace character is '}' and return -3 if the first
+** non-whitespace character is ']'.
 */
-static void rtreeRelease(Rtree *pRtree){
-  pRtree->nBusy--;
-  if( pRtree->nBusy==0 ){
-    pRtree->inWrTrans = 0;
-    assert( pRtree->nCursor==0 );
-    nodeBlobReset(pRtree);
-    assert( pRtree->nNodeRef==0 );
-    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_finalize(pRtree->pWriteAux);
-    sqlite3_free(pRtree->zReadAuxSql);
-    sqlite3_free(pRtree);
+static int jsonParseValue(JsonParse *pParse, u32 i){
+  char c;
+  u32 j;
+  int iThis;
+  int x;
+  JsonNode *pNode;
+  const char *z = pParse->zJson;
+  while( safe_isspace(z[i]) ){ i++; }
+  if( (c = z[i])=='{' ){
+    /* Parse object */
+    iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
+    if( iThis<0 ) return -1;
+    for(j=i+1;;j++){
+      while( safe_isspace(z[j]) ){ j++; }
+      if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
+      x = jsonParseValue(pParse, j);
+      if( x<0 ){
+        pParse->iDepth--;
+        if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1;
+        return -1;
+      }
+      if( pParse->oom ) return -1;
+      pNode = &pParse->aNode[pParse->nNode-1];
+      if( pNode->eType!=JSON_STRING ) return -1;
+      pNode->jnFlags |= JNODE_LABEL;
+      j = x;
+      while( safe_isspace(z[j]) ){ j++; }
+      if( z[j]!=':' ) return -1;
+      j++;
+      x = jsonParseValue(pParse, j);
+      pParse->iDepth--;
+      if( x<0 ) return -1;
+      j = x;
+      while( safe_isspace(z[j]) ){ j++; }
+      c = z[j];
+      if( c==',' ) continue;
+      if( c!='}' ) return -1;
+      break;
+    }
+    pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
+    return j+1;
+  }else if( c=='[' ){
+    /* Parse array */
+    iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
+    if( iThis<0 ) return -1;
+    for(j=i+1;;j++){
+      while( safe_isspace(z[j]) ){ j++; }
+      if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
+      x = jsonParseValue(pParse, j);
+      pParse->iDepth--;
+      if( x<0 ){
+        if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1;
+        return -1;
+      }
+      j = x;
+      while( safe_isspace(z[j]) ){ j++; }
+      c = z[j];
+      if( c==',' ) continue;
+      if( c!=']' ) return -1;
+      break;
+    }
+    pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
+    return j+1;
+  }else if( c=='"' ){
+    /* Parse string */
+    u8 jnFlags = 0;
+    j = i+1;
+    for(;;){
+      c = z[j];
+      if( (c & ~0x1f)==0 ){
+        /* Control characters are not allowed in strings */
+        return -1;
+      }
+      if( c=='\\' ){
+        c = z[++j];
+        if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
+           || c=='n' || c=='r' || c=='t'
+           || (c=='u' && jsonIs4Hex(z+j+1)) ){
+          jnFlags = JNODE_ESCAPE;
+        }else{
+          return -1;
+        }
+      }else if( c=='"' ){
+        break;
+      }
+      j++;
+    }
+    jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]);
+    if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags;
+    return j+1;
+  }else if( c=='n'
+         && strncmp(z+i,"null",4)==0
+         && !safe_isalnum(z[i+4]) ){
+    jsonParseAddNode(pParse, JSON_NULL, 0, 0);
+    return i+4;
+  }else if( c=='t'
+         && strncmp(z+i,"true",4)==0
+         && !safe_isalnum(z[i+4]) ){
+    jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
+    return i+4;
+  }else if( c=='f'
+         && strncmp(z+i,"false",5)==0
+         && !safe_isalnum(z[i+5]) ){
+    jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
+    return i+5;
+  }else if( c=='-' || (c>='0' && c<='9') ){
+    /* Parse number */
+    u8 seenDP = 0;
+    u8 seenE = 0;
+    assert( '-' < '0' );
+    if( c<='0' ){
+      j = c=='-' ? i+1 : i;
+      if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1;
+    }
+    j = i+1;
+    for(;; j++){
+      c = z[j];
+      if( c>='0' && c<='9' ) continue;
+      if( c=='.' ){
+        if( z[j-1]=='-' ) return -1;
+        if( seenDP ) return -1;
+        seenDP = 1;
+        continue;
+      }
+      if( c=='e' || c=='E' ){
+        if( z[j-1]<'0' ) return -1;
+        if( seenE ) return -1;
+        seenDP = seenE = 1;
+        c = z[j+1];
+        if( c=='+' || c=='-' ){
+          j++;
+          c = z[j+1];
+        }
+        if( c<'0' || c>'9' ) return -1;
+        continue;
+      }
+      break;
+    }
+    if( z[j-1]<'0' ) return -1;
+    jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT,
+                        j - i, &z[i]);
+    return j;
+  }else if( c=='}' ){
+    return -2;  /* End of {...} */
+  }else if( c==']' ){
+    return -3;  /* End of [...] */
+  }else if( c==0 ){
+    return 0;   /* End of file */
+  }else{
+    return -1;  /* Syntax error */
   }
 }
 
-/* 
-** Rtree virtual table module xDisconnect method.
-*/
-static int rtreeDisconnect(sqlite3_vtab *pVtab){
-  rtreeRelease((Rtree *)pVtab);
-  return SQLITE_OK;
-}
-
-/* 
-** Rtree virtual table module xDestroy method.
+/*
+** Parse a complete JSON string.  Return 0 on success or non-zero if there
+** are any errors.  If an error occurs, free all memory associated with
+** pParse.
+**
+** pParse is uninitialized when this routine is called.
 */
-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);
+static int jsonParse(
+  JsonParse *pParse,           /* Initialize and fill this JsonParse object */
+  sqlite3_context *pCtx,       /* Report errors here */
+  const char *zJson            /* Input JSON text to be parsed */
+){
+  int i;
+  memset(pParse, 0, sizeof(*pParse));
+  if( zJson==0 ) return 1;
+  pParse->zJson = zJson;
+  i = jsonParseValue(pParse, 0);
+  if( pParse->oom ) i = -1;
+  if( i>0 ){
+    assert( pParse->iDepth==0 );
+    while( safe_isspace(zJson[i]) ) i++;
+    if( zJson[i] ) i = -1;
   }
-  if( rc==SQLITE_OK ){
-    rtreeRelease(pRtree);
+  if( i<=0 ){
+    if( pCtx!=0 ){
+      if( pParse->oom ){
+        sqlite3_result_error_nomem(pCtx);
+      }else{
+        sqlite3_result_error(pCtx, "malformed JSON", -1);
+      }
+    }
+    jsonParseReset(pParse);
+    return 1;
   }
-
-  return rc;
+  return 0;
 }
 
-/* 
-** Rtree virtual table module xOpen method.
+/* Mark node i of pParse as being a child of iParent.  Call recursively
+** to fill in all the descendants of node i.
 */
-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++;
+static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){
+  JsonNode *pNode = &pParse->aNode[i];
+  u32 j;
+  pParse->aUp[i] = iParent;
+  switch( pNode->eType ){
+    case JSON_ARRAY: {
+      for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){
+        jsonParseFillInParentage(pParse, i+j, i);
+      }
+      break;
+    }
+    case JSON_OBJECT: {
+      for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j+1)+1){
+        pParse->aUp[i+j] = i;
+        jsonParseFillInParentage(pParse, i+j+1, i);
+      }
+      break;
+    }
+    default: {
+      break;
+    }
   }
-  *ppCursor = (sqlite3_vtab_cursor *)pCsr;
-
-  return rc;
 }
 
-
 /*
-** Free the RtreeCursor.aConstraint[] array and its contents.
+** Compute the parentage of all nodes in a completed parse.
 */
-static void freeCursorConstraints(RtreeCursor *pCsr){
-  if( pCsr->aConstraint ){
-    int i;                        /* Used to iterate through constraint array */
-    for(i=0; i<pCsr->nConstraint; 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;
+static int jsonParseFindParents(JsonParse *pParse){
+  u32 *aUp;
+  assert( pParse->aUp==0 );
+  aUp = pParse->aUp = sqlite3_malloc( sizeof(u32)*pParse->nNode );
+  if( aUp==0 ){
+    pParse->oom = 1;
+    return SQLITE_NOMEM;
   }
+  jsonParseFillInParentage(pParse, 0, 0);
+  return SQLITE_OK;
 }
 
-/* 
-** Rtree virtual table module xClose method.
+/*
+** Magic number used for the JSON parse cache in sqlite3_get_auxdata()
 */
-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_finalize(pCsr->pReadAux);
-  sqlite3_free(pCsr->aPoint);
-  for(ii=0; ii<RTREE_CACHE_SZ; ii++) nodeRelease(pRtree, pCsr->aNode[ii]);
-  sqlite3_free(pCsr);
-  pRtree->nCursor--;
-  nodeBlobReset(pRtree);
-  return SQLITE_OK;
-}
+#define JSON_CACHE_ID  (-429938)  /* First cache entry */
+#define JSON_CACHE_SZ  4          /* Max number of cache entries */
 
 /*
-** 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.
+** Obtain a complete parse of the JSON found in the first argument
+** of the argv array.  Use the sqlite3_get_auxdata() cache for this
+** parse if it is available.  If the cache is not available or if it
+** is no longer valid, parse the JSON again and return the new parse,
+** and also register the new parse so that it will be available for
+** future sqlite3_get_auxdata() calls.
 */
-static int rtreeEof(sqlite3_vtab_cursor *cur){
-  RtreeCursor *pCsr = (RtreeCursor *)cur;
-  return pCsr->atEOF;
+static JsonParse *jsonParseCached(
+  sqlite3_context *pCtx,
+  sqlite3_value **argv,
+  sqlite3_context *pErrCtx
+){
+  const char *zJson = (const char*)sqlite3_value_text(argv[0]);
+  int nJson = sqlite3_value_bytes(argv[0]);
+  JsonParse *p;
+  JsonParse *pMatch = 0;
+  int iKey;
+  int iMinKey = 0;
+  u32 iMinHold = 0xffffffff;
+  u32 iMaxHold = 0;
+  if( zJson==0 ) return 0;
+  for(iKey=0; iKey<JSON_CACHE_SZ; iKey++){
+    p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iKey);
+    if( p==0 ){
+      iMinKey = iKey;
+      break;
+    }
+    if( pMatch==0
+     && p->nJson==nJson
+     && memcmp(p->zJson,zJson,nJson)==0
+    ){
+      p->nErr = 0;
+      pMatch = p;
+    }else if( p->iHold<iMinHold ){
+      iMinHold = p->iHold;
+      iMinKey = iKey;
+    }
+    if( p->iHold>iMaxHold ){
+      iMaxHold = p->iHold;
+    }
+  }
+  if( pMatch ){
+    pMatch->nErr = 0;
+    pMatch->iHold = iMaxHold+1;
+    return pMatch;
+  }
+  p = sqlite3_malloc( sizeof(*p) + nJson + 1 );
+  if( p==0 ){
+    sqlite3_result_error_nomem(pCtx);
+    return 0;
+  }
+  memset(p, 0, sizeof(*p));
+  p->zJson = (char*)&p[1];
+  memcpy((char*)p->zJson, zJson, nJson+1);
+  if( jsonParse(p, pErrCtx, p->zJson) ){
+    sqlite3_free(p);
+    return 0;
+  }
+  p->nJson = nJson;
+  p->iHold = iMaxHold+1;
+  sqlite3_set_auxdata(pCtx, JSON_CACHE_ID+iMinKey, p,
+                      (void(*)(void*))jsonParseFree);
+  return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iMinKey);
 }
 
 /*
-** 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.
+** Compare the OBJECT label at pNode against zKey,nKey.  Return true on
+** a match.
 */
-#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; \
+static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){
+  if( pNode->jnFlags & JNODE_RAW ){
+    if( pNode->n!=nKey ) return 0;
+    return strncmp(pNode->u.zJContent, zKey, nKey)==0;
+  }else{
+    if( pNode->n!=nKey+2 ) return 0;
+    return strncmp(pNode->u.zJContent+1, zKey, nKey)==0;
+  }
 }
-#endif
+
+/* forward declaration */
+static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**);
 
 /*
-** Check the RTree node or entry given by pCellData and p against the MATCH
-** constraint pConstraint.  
+** Search along zPath to find the node specified.  Return a pointer
+** to that node, or NULL if zPath is malformed or if there is no such
+** node.
+**
+** If pApnd!=0, then try to append new nodes to complete zPath if it is
+** possible to do so and if no existing node corresponds to zPath.  If
+** new nodes are appended *pApnd is set to 1.
 */
-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 */
+static JsonNode *jsonLookupStep(
+  JsonParse *pParse,      /* The JSON to search */
+  u32 iRoot,              /* Begin the search at this node */
+  const char *zPath,      /* The path to search */
+  int *pApnd,             /* Append nodes to complete path if not NULL */
+  const char **pzErr      /* Make *pzErr point to any syntax error in zPath */
 ){
-  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;
+  u32 i, j, nKey;
+  const char *zKey;
+  JsonNode *pRoot = &pParse->aNode[iRoot];
+  if( zPath[0]==0 ) return pRoot;
+  if( zPath[0]=='.' ){
+    if( pRoot->eType!=JSON_OBJECT ) return 0;
+    zPath++;
+    if( zPath[0]=='"' ){
+      zKey = zPath + 1;
+      for(i=1; zPath[i] && zPath[i]!='"'; i++){}
+      nKey = i-1;
+      if( zPath[i] ){
+        i++;
+      }else{
+        *pzErr = zPath;
+        return 0;
+      }
+    }else{
+      zKey = zPath;
+      for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){}
+      nKey = i;
     }
-  }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( nKey==0 ){
+      *pzErr = zPath;
+      return 0;
     }
-  }
-  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 || *prScore<RTREE_ZERO ){
-      *prScore = pInfo->rScore;
+    j = 1;
+    for(;;){
+      while( j<=pRoot->n ){
+        if( jsonLabelCompare(pRoot+j, zKey, nKey) ){
+          return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr);
+        }
+        j++;
+        j += jsonNodeSize(&pRoot[j]);
+      }
+      if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
+      iRoot += pRoot->u.iAppend;
+      pRoot = &pParse->aNode[iRoot];
+      j = 1;
+    }
+    if( pApnd ){
+      u32 iStart, iLabel;
+      JsonNode *pNode;
+      iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
+      iLabel = jsonParseAddNode(pParse, JSON_STRING, i, zPath);
+      zPath += i;
+      pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
+      if( pParse->oom ) return 0;
+      if( pNode ){
+        pRoot = &pParse->aNode[iRoot];
+        pRoot->u.iAppend = iStart - iRoot;
+        pRoot->jnFlags |= JNODE_APPEND;
+        pParse->aNode[iLabel].jnFlags |= JNODE_RAW;
+      }
+      return pNode;
+    }
+  }else if( zPath[0]=='[' && safe_isdigit(zPath[1]) ){
+    if( pRoot->eType!=JSON_ARRAY ) return 0;
+    i = 0;
+    j = 1;
+    while( safe_isdigit(zPath[j]) ){
+      i = i*10 + zPath[j] - '0';
+      j++;
+    }
+    if( zPath[j]!=']' ){
+      *pzErr = zPath;
+      return 0;
+    }
+    zPath += j + 1;
+    j = 1;
+    for(;;){
+      while( j<=pRoot->n && (i>0 || (pRoot[j].jnFlags & JNODE_REMOVE)!=0) ){
+        if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 ) i--;
+        j += jsonNodeSize(&pRoot[j]);
+      }
+      if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
+      iRoot += pRoot->u.iAppend;
+      pRoot = &pParse->aNode[iRoot];
+      j = 1;
+    }
+    if( j<=pRoot->n ){
+      return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr);
+    }
+    if( i==0 && pApnd ){
+      u32 iStart;
+      JsonNode *pNode;
+      iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0);
+      pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
+      if( pParse->oom ) return 0;
+      if( pNode ){
+        pRoot = &pParse->aNode[iRoot];
+        pRoot->u.iAppend = iStart - iRoot;
+        pRoot->jnFlags |= JNODE_APPEND;
+      }
+      return pNode;
     }
+  }else{
+    *pzErr = zPath;
   }
-  return rc;
+  return 0;
 }
 
-/* 
-** 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.
+/*
+** Append content to pParse that will complete zPath.  Return a pointer
+** to the inserted node, or return NULL if the append fails.
 */
-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 */
+static JsonNode *jsonLookupAppend(
+  JsonParse *pParse,     /* Append content to the JSON parse */
+  const char *zPath,     /* Description of content to append */
+  int *pApnd,            /* Set this flag to 1 */
+  const char **pzErr     /* Make this point to any syntax error */
 ){
-  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;
+  *pApnd = 1;
+  if( zPath[0]==0 ){
+    jsonParseAddNode(pParse, JSON_NULL, 0, 0);
+    return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1];
   }
-  *peWithin = NOT_WITHIN;
+  if( zPath[0]=='.' ){
+    jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
+  }else if( strncmp(zPath,"[0]",3)==0 ){
+    jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
+  }else{
+    return 0;
+  }
+  if( pParse->oom ) return 0;
+  return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr);
 }
 
 /*
-** 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.
+** Return the text of a syntax error message on a JSON path.  Space is
+** obtained from sqlite3_malloc().
+*/
+static char *jsonPathSyntaxError(const char *zErr){
+  return sqlite3_mprintf("JSON path error near '%q'", zErr);
+}
+
+/*
+** Do a node lookup using zPath.  Return a pointer to the node on success.
+** Return NULL if not found or if there is an error.
 **
-** The constraint is of the form:  xN op $val
+** On an error, write an error message into pCtx and increment the
+** pParse->nErr counter.
 **
-** The op is given by p->op.  The xN is p->iCoord-th coordinate in
-** pCellData.  $val is given by p->u.rValue.
+** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if
+** nodes are appended.
 */
-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 */
+static JsonNode *jsonLookup(
+  JsonParse *pParse,      /* The JSON to search */
+  const char *zPath,      /* The path to search */
+  int *pApnd,             /* Append nodes to complete path if not NULL */
+  sqlite3_context *pCtx   /* Report errors here, if not NULL */
 ){
-  RtreeDValue xN;      /* Coordinate value converted to a double */
+  const char *zErr = 0;
+  JsonNode *pNode = 0;
+  char *zMsg;
 
-  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;
+  if( zPath==0 ) return 0;
+  if( zPath[0]!='$' ){
+    zErr = zPath;
+    goto lookup_err;
   }
-  *peWithin = NOT_WITHIN;
+  zPath++;
+  pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr);
+  if( zErr==0 ) return pNode;
+
+lookup_err:
+  pParse->nErr++;
+  assert( zErr!=0 && pCtx!=0 );
+  zMsg = jsonPathSyntaxError(zErr);
+  if( zMsg ){
+    sqlite3_result_error(pCtx, zMsg, -1);
+    sqlite3_free(zMsg);
+  }else{
+    sqlite3_result_error_nomem(pCtx);
+  }
+  return 0;
 }
 
+
 /*
-** 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.
+** Report the wrong number of arguments for json_insert(), json_replace()
+** or json_set().
 */
-static int nodeRowidIndex(
-  Rtree *pRtree, 
-  RtreeNode *pNode, 
-  i64 iRowid,
-  int *piIndex
+static void jsonWrongNumArgs(
+  sqlite3_context *pCtx,
+  const char *zFuncName
 ){
-  int ii;
-  int nCell = NCELL(pNode);
-  assert( nCell<200 );
-  for(ii=0; ii<nCell; ii++){
-    if( nodeGetRowid(pRtree, pNode, ii)==iRowid ){
-      *piIndex = ii;
-      return SQLITE_OK;
-    }
-  }
-  return SQLITE_CORRUPT_VTAB;
+  char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments",
+                               zFuncName);
+  sqlite3_result_error(pCtx, zMsg, -1);
+  sqlite3_free(zMsg);     
 }
 
 /*
-** Return the index of the cell containing a pointer to node pNode
-** in its parent. If pNode is the root node, return -1.
+** Mark all NULL entries in the Object passed in as JNODE_REMOVE.
 */
-static int nodeParentIndex(Rtree *pRtree, RtreeNode *pNode, int *piIndex){
-  RtreeNode *pParent = pNode->pParent;
-  if( pParent ){
-    return nodeRowidIndex(pRtree, pParent, pNode->iNode, piIndex);
+static void jsonRemoveAllNulls(JsonNode *pNode){
+  int i, n;
+  assert( pNode->eType==JSON_OBJECT );
+  n = pNode->n;
+  for(i=2; i<=n; i += jsonNodeSize(&pNode[i])+1){
+    switch( pNode[i].eType ){
+      case JSON_NULL:
+        pNode[i].jnFlags |= JNODE_REMOVE;
+        break;
+      case JSON_OBJECT:
+        jsonRemoveAllNulls(&pNode[i]);
+        break;
+    }
   }
-  *piIndex = -1;
-  return SQLITE_OK;
 }
 
+
+/****************************************************************************
+** SQL functions used for testing and debugging
+****************************************************************************/
+
+#ifdef SQLITE_DEBUG
 /*
-** 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.
+** The json_parse(JSON) function returns a string which describes
+** a parse of the JSON provided.  Or it returns NULL if JSON is not
+** well-formed.
 */
-static int rtreeSearchPointCompare(
-  const RtreeSearchPoint *pA,
-  const RtreeSearchPoint *pB
+static void jsonParseFunc(
+  sqlite3_context *ctx,
+  int argc,
+  sqlite3_value **argv
 ){
-  if( pA->rScore<pB->rScore ) return -1;
-  if( pA->rScore>pB->rScore ) return +1;
-  if( pA->iLevel<pB->iLevel ) return -1;
-  if( pA->iLevel>pB->iLevel ) return +1;
-  return 0;
-}
+  JsonString s;       /* Output string - not real JSON */
+  JsonParse x;        /* The parse */
+  u32 i;
 
-/*
-** Interchange two search points in a cursor.
-*/
-static void rtreeSearchPointSwap(RtreeCursor *p, int i, int j){
-  RtreeSearchPoint t = p->aPoint[i];
-  assert( i<j );
-  p->aPoint[i] = p->aPoint[j];
-  p->aPoint[j] = t;
-  i++; j++;
-  if( i<RTREE_CACHE_SZ ){
-    if( j>=RTREE_CACHE_SZ ){
-      nodeRelease(RTREE_OF_CURSOR(p), p->aNode[i]);
-      p->aNode[i] = 0;
+  assert( argc==1 );
+  if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
+  jsonParseFindParents(&x);
+  jsonInit(&s, ctx);
+  for(i=0; i<x.nNode; i++){
+    const char *zType;
+    if( x.aNode[i].jnFlags & JNODE_LABEL ){
+      assert( x.aNode[i].eType==JSON_STRING );
+      zType = "label";
     }else{
-      RtreeNode *pTemp = p->aNode[i];
-      p->aNode[i] = p->aNode[j];
-      p->aNode[j] = pTemp;
+      zType = jsonType[x.aNode[i].eType];
+    }
+    jsonPrintf(100, &s,"node %3u: %7s n=%-4d up=%-4d",
+               i, zType, x.aNode[i].n, x.aUp[i]);
+    if( x.aNode[i].u.zJContent!=0 ){
+      jsonAppendRaw(&s, " ", 1);
+      jsonAppendRaw(&s, x.aNode[i].u.zJContent, x.aNode[i].n);
     }
+    jsonAppendRaw(&s, "\n", 1);
   }
+  jsonParseReset(&x);
+  jsonResult(&s);
 }
 
 /*
-** Return the search point with the lowest current score.
+** The json_test1(JSON) function return true (1) if the input is JSON
+** text generated by another json function.  It returns (0) if the input
+** is not known to be JSON.
 */
-static RtreeSearchPoint *rtreeSearchPointFirst(RtreeCursor *pCur){
-  return pCur->bPoint ? &pCur->sPoint : pCur->nPoint ? pCur->aPoint : 0;
+static void jsonTest1Func(
+  sqlite3_context *ctx,
+  int argc,
+  sqlite3_value **argv
+){
+  UNUSED_PARAM(argc);
+  sqlite3_result_int(ctx, sqlite3_value_subtype(argv[0])==JSON_SUBTYPE);
 }
+#endif /* SQLITE_DEBUG */
+
+/****************************************************************************
+** Scalar SQL function implementations
+****************************************************************************/
 
 /*
-** Get the RtreeNode for the search point with the lowest score.
+** Implementation of the json_QUOTE(VALUE) function.  Return a JSON value
+** corresponding to the SQL value input.  Mostly this means putting 
+** double-quotes around strings and returning the unquoted string "null"
+** when given a NULL input.
 */
-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];
+static void jsonQuoteFunc(
+  sqlite3_context *ctx,
+  int argc,
+  sqlite3_value **argv
+){
+  JsonString jx;
+  UNUSED_PARAM(argc);
+
+  jsonInit(&jx, ctx);
+  jsonAppendValue(&jx, argv[0]);
+  jsonResult(&jx);
+  sqlite3_result_subtype(ctx, JSON_SUBTYPE);
 }
 
 /*
-** Push a new element onto the priority queue
+** Implementation of the json_array(VALUE,...) function.  Return a JSON
+** array that contains all values given in arguments.  Or if any argument
+** is a BLOB, throw an error.
 */
-static RtreeSearchPoint *rtreeEnqueue(
-  RtreeCursor *pCur,    /* The cursor */
-  RtreeDValue rScore,   /* Score for the new search point */
-  u8 iLevel             /* Level for the new search point */
+static void jsonArrayFunc(
+  sqlite3_context *ctx,
+  int argc,
+  sqlite3_value **argv
 ){
-  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;
+  int i;
+  JsonString jx;
+
+  jsonInit(&jx, ctx);
+  jsonAppendChar(&jx, '[');
+  for(i=0; i<argc; i++){
+    jsonAppendSeparator(&jx);
+    jsonAppendValue(&jx, argv[i]);
   }
-  return pNew;
+  jsonAppendChar(&jx, ']');
+  jsonResult(&jx);
+  sqlite3_result_subtype(ctx, JSON_SUBTYPE);
 }
 
+
 /*
-** Allocate a new RtreeSearchPoint and return a pointer to it.  Return
-** NULL if malloc fails.
+** json_array_length(JSON)
+** json_array_length(JSON, PATH)
+**
+** Return the number of elements in the top-level JSON array.  
+** Return 0 if the input is not a well-formed JSON array.
 */
-static RtreeSearchPoint *rtreeSearchPointNew(
-  RtreeCursor *pCur,    /* The cursor */
-  RtreeDValue rScore,   /* Score for the new search point */
-  u8 iLevel             /* Level for the new search point */
+static void jsonArrayLengthFunc(
+  sqlite3_context *ctx,
+  int argc,
+  sqlite3_value **argv
 ){
-  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( ii<RTREE_CACHE_SZ ){
-        assert( pCur->aNode[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);
-  }
-}
+  JsonParse *p;          /* The parse */
+  sqlite3_int64 n = 0;
+  u32 i;
+  JsonNode *pNode;
 
-#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( idx<RTREE_CACHE_SZ ){
-    printf(" %p\n", pCur->aNode[idx]);
+  p = jsonParseCached(ctx, argv, ctx);
+  if( p==0 ) return;
+  assert( p->nNode );
+  if( argc==2 ){
+    const char *zPath = (const char*)sqlite3_value_text(argv[1]);
+    pNode = jsonLookup(p, zPath, 0, ctx);
   }else{
-    printf("\n");
+    pNode = p->aNode;
   }
-}
-static void traceQueue(RtreeCursor *pCur, const char *zPrefix){
-  int ii;
-  printf("=== %9s ", zPrefix);
-  if( pCur->bPoint ){
-    tracePoint(&pCur->sPoint, -1, pCur);
+  if( pNode==0 ){
+    return;
   }
-  for(ii=0; ii<pCur->nPoint; ii++){
-    if( ii>0 || pCur->bPoint ) printf("              ");
-    tracePoint(&pCur->aPoint[ii], ii, pCur);
+  if( pNode->eType==JSON_ARRAY ){
+    assert( (pNode->jnFlags & JNODE_APPEND)==0 );
+    for(i=1; i<=pNode->n; n++){
+      i += jsonNodeSize(&pNode[i]);
+    }
   }
+  sqlite3_result_int64(ctx, n);
 }
-# 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.
+/*
+** json_extract(JSON, PATH, ...)
+**
+** Return the element described by PATH.  Return NULL if there is no
+** PATH element.  If there are multiple PATHs, then return a JSON array
+** with the result from each path.  Throw an error if the JSON or any PATH
+** is malformed.
 */
-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( n<RTREE_CACHE_SZ-1 ){
-      p->aNode[1] = p->aNode[n+1];
-      p->aNode[n+1] = 0;
-    }
-    i = 0;
-    while( (j = i*2+1)<n ){
-      k = j+1;
-      if( k<n && rtreeSearchPointCompare(&p->aPoint[k], &p->aPoint[j])<0 ){
-        if( rtreeSearchPointCompare(&p->aPoint[k], &p->aPoint[i])<0 ){
-          rtreeSearchPointSwap(p, i, k);
-          i = k;
-        }else{
-          break;
-        }
+static void jsonExtractFunc(
+  sqlite3_context *ctx,
+  int argc,
+  sqlite3_value **argv
+){
+  JsonParse *p;          /* The parse */
+  JsonNode *pNode;
+  const char *zPath;
+  JsonString jx;
+  int i;
+
+  if( argc<2 ) return;
+  p = jsonParseCached(ctx, argv, ctx);
+  if( p==0 ) return;
+  jsonInit(&jx, ctx);
+  jsonAppendChar(&jx, '[');
+  for(i=1; i<argc; i++){
+    zPath = (const char*)sqlite3_value_text(argv[i]);
+    pNode = jsonLookup(p, zPath, 0, ctx);
+    if( p->nErr ) break;
+    if( argc>2 ){
+      jsonAppendSeparator(&jx);
+      if( pNode ){
+        jsonRenderNode(pNode, &jx, 0);
       }else{
-        if( rtreeSearchPointCompare(&p->aPoint[j], &p->aPoint[i])<0 ){
-          rtreeSearchPointSwap(p, i, j);
-          i = j;
-        }else{
-          break;
-        }
+        jsonAppendRaw(&jx, "null", 4);
       }
+    }else if( pNode ){
+      jsonReturn(pNode, ctx, 0);
     }
   }
+  if( argc>2 && i==argc ){
+    jsonAppendChar(&jx, ']');
+    jsonResult(&jx);
+    sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+  }
+  jsonReset(&jx);
 }
 
-
-/*
-** 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.
+/* This is the RFC 7396 MergePatch algorithm.
 */
-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->iCell<nCell ){
-      sqlite3_rtree_dbl rScore = (sqlite3_rtree_dbl)-1;
-      u8 *pCellData = pNode->zData + (4+pRtree->nBytesPerCell*p->iCell);
-      eWithin = FULLY_WITHIN;
-      for(ii=0; ii<nConstraint; ii++){
-        RtreeConstraint *pConstraint = pCur->aConstraint + 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);
+static JsonNode *jsonMergePatch(
+  JsonParse *pParse,   /* The JSON parser that contains the TARGET */
+  u32 iTarget,         /* Node of the TARGET in pParse */
+  JsonNode *pPatch     /* The PATCH */
+){
+  u32 i, j;
+  u32 iRoot;
+  JsonNode *pTarget;
+  if( pPatch->eType!=JSON_OBJECT ){
+    return pPatch;
+  }
+  assert( iTarget>=0 && iTarget<pParse->nNode );
+  pTarget = &pParse->aNode[iTarget];
+  assert( (pPatch->jnFlags & JNODE_APPEND)==0 );
+  if( pTarget->eType!=JSON_OBJECT ){
+    jsonRemoveAllNulls(pPatch);
+    return pPatch;
+  }
+  iRoot = iTarget;
+  for(i=1; i<pPatch->n; i += jsonNodeSize(&pPatch[i+1])+1){
+    u32 nKey;
+    const char *zKey;
+    assert( pPatch[i].eType==JSON_STRING );
+    assert( pPatch[i].jnFlags & JNODE_LABEL );
+    nKey = pPatch[i].n;
+    zKey = pPatch[i].u.zJContent;
+    assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
+    for(j=1; j<pTarget->n; j += jsonNodeSize(&pTarget[j+1])+1 ){
+      assert( pTarget[j].eType==JSON_STRING );
+      assert( pTarget[j].jnFlags & JNODE_LABEL );
+      assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
+      if( pTarget[j].n==nKey && strncmp(pTarget[j].u.zJContent,zKey,nKey)==0 ){
+        if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_PATCH) ) break;
+        if( pPatch[i+1].eType==JSON_NULL ){
+          pTarget[j+1].jnFlags |= JNODE_REMOVE;
         }else{
-          rtreeNonleafConstraint(pConstraint, eInt, pCellData, &eWithin);
+          JsonNode *pNew = jsonMergePatch(pParse, iTarget+j+1, &pPatch[i+1]);
+          if( pNew==0 ) return 0;
+          pTarget = &pParse->aNode[iTarget];
+          if( pNew!=&pTarget[j+1] ){
+            pTarget[j+1].u.pPatch = pNew;
+            pTarget[j+1].jnFlags |= JNODE_PATCH;
+          }
         }
-        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);
+        break;
       }
-      if( rScore<RTREE_ZERO ) rScore = RTREE_ZERO;
-      p = rtreeSearchPointNew(pCur, rScore, x.iLevel);
-      if( p==0 ) return SQLITE_NOMEM;
-      p->eWithin = (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);
+    if( j>=pTarget->n && pPatch[i+1].eType!=JSON_NULL ){
+      int iStart, iPatch;
+      iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
+      jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
+      iPatch = jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
+      if( pParse->oom ) return 0;
+      jsonRemoveAllNulls(pPatch);
+      pTarget = &pParse->aNode[iTarget];
+      pParse->aNode[iRoot].jnFlags |= JNODE_APPEND;
+      pParse->aNode[iRoot].u.iAppend = iStart - iRoot;
+      iRoot = iStart;
+      pParse->aNode[iPatch].jnFlags |= JNODE_PATCH;
+      pParse->aNode[iPatch].u.pPatch = &pPatch[i+1];
     }
   }
-  pCur->atEOF = p==0;
-  return SQLITE_OK;
+  return pTarget;
 }
 
-/* 
-** Rtree virtual table module xNext method.
+/*
+** Implementation of the json_mergepatch(JSON1,JSON2) function.  Return a JSON
+** object that is the result of running the RFC 7396 MergePatch() algorithm
+** on the two arguments.
 */
-static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){
-  RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor;
-  int rc = SQLITE_OK;
+static void jsonPatchFunc(
+  sqlite3_context *ctx,
+  int argc,
+  sqlite3_value **argv
+){
+  JsonParse x;     /* The JSON that is being patched */
+  JsonParse y;     /* The patch */
+  JsonNode *pResult;   /* The result of the merge */
 
-  /* Move to the next entry that matches the configured constraints. */
-  RTREE_QUEUE_TRACE(pCsr, "POP-Nx:");
-  if( pCsr->bAuxValid ){
-    pCsr->bAuxValid = 0;
-    sqlite3_reset(pCsr->pReadAux);
+  UNUSED_PARAM(argc);
+  if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
+  if( jsonParse(&y, ctx, (const char*)sqlite3_value_text(argv[1])) ){
+    jsonParseReset(&x);
+    return;
   }
-  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);
+  pResult = jsonMergePatch(&x, 0, y.aNode);
+  assert( pResult!=0 || x.oom );
+  if( pResult ){
+    jsonReturnJson(pResult, ctx, 0);
+  }else{
+    sqlite3_result_error_nomem(ctx);
   }
-  return rc;
+  jsonParseReset(&x);
+  jsonParseReset(&y);
 }
 
-/* 
-** Rtree virtual table module xColumn method.
+
+/*
+** Implementation of the json_object(NAME,VALUE,...) function.  Return a JSON
+** object that contains all name/value given in arguments.  Or if any name
+** is not a string or if any value is a BLOB, throw an error.
 */
-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);
+static void jsonObjectFunc(
+  sqlite3_context *ctx,
+  int argc,
+  sqlite3_value **argv
+){
+  int i;
+  JsonString jx;
+  const char *z;
+  u32 n;
 
-  if( rc ) return rc;
-  if( p==0 ) return SQLITE_OK;
-  if( i==0 ){
-    sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell));
-  }else if( i<=pRtree->nDim2 ){
-    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);
-    }
-  }else{
-    if( !pCsr->bAuxValid ){
-      if( pCsr->pReadAux==0 ){
-        rc = sqlite3_prepare_v3(pRtree->db, pRtree->zReadAuxSql, -1, 0,
-                                &pCsr->pReadAux, 0);
-        if( rc ) return rc;
-      }
-      sqlite3_bind_int64(pCsr->pReadAux, 1, 
-          nodeGetRowid(pRtree, pNode, p->iCell));
-      rc = sqlite3_step(pCsr->pReadAux);
-      if( rc==SQLITE_ROW ){
-        pCsr->bAuxValid = 1;
-      }else{
-        sqlite3_reset(pCsr->pReadAux);
-        if( rc==SQLITE_DONE ) rc = SQLITE_OK;
-        return rc;
-      }
+  if( argc&1 ){
+    sqlite3_result_error(ctx, "json_object() requires an even number "
+                                  "of arguments", -1);
+    return;
+  }
+  jsonInit(&jx, ctx);
+  jsonAppendChar(&jx, '{');
+  for(i=0; i<argc; i+=2){
+    if( sqlite3_value_type(argv[i])!=SQLITE_TEXT ){
+      sqlite3_result_error(ctx, "json_object() labels must be TEXT", -1);
+      jsonReset(&jx);
+      return;
     }
-    sqlite3_result_value(ctx,
-         sqlite3_column_value(pCsr->pReadAux, i - pRtree->nDim2 + 1));
-  }  
-  return SQLITE_OK;
+    jsonAppendSeparator(&jx);
+    z = (const char*)sqlite3_value_text(argv[i]);
+    n = (u32)sqlite3_value_bytes(argv[i]);
+    jsonAppendString(&jx, z, n);
+    jsonAppendChar(&jx, ':');
+    jsonAppendValue(&jx, argv[i+1]);
+  }
+  jsonAppendChar(&jx, '}');
+  jsonResult(&jx);
+  sqlite3_result_subtype(ctx, JSON_SUBTYPE);
 }
 
-/* 
-** 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.
+
+/*
+** json_remove(JSON, PATH, ...)
+**
+** Remove the named elements from JSON and return the result.  malformed
+** JSON or PATH arguments result in an error.
 */
-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 */
+static void jsonRemoveFunc(
+  sqlite3_context *ctx,
+  int argc,
+  sqlite3_value **argv
 ){
-  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);
+  JsonParse x;          /* The parse */
+  JsonNode *pNode;
+  const char *zPath;
+  u32 i;
+
+  if( argc<1 ) return;
+  if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
+  assert( x.nNode );
+  for(i=1; i<(u32)argc; i++){
+    zPath = (const char*)sqlite3_value_text(argv[i]);
+    if( zPath==0 ) goto remove_done;
+    pNode = jsonLookup(&x, zPath, 0, ctx);
+    if( x.nErr ) goto remove_done;
+    if( pNode ) pNode->jnFlags |= JNODE_REMOVE;
   }
-  return rc;
+  if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){
+    jsonReturnJson(x.aNode, ctx, 0);
+  }
+remove_done:
+  jsonParseReset(&x);
 }
 
 /*
-** 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.
+** json_replace(JSON, PATH, VALUE, ...)
+**
+** Replace the value at PATH with VALUE.  If PATH does not already exist,
+** this routine is a no-op.  If JSON or PATH is malformed, throw an error.
 */
-static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){
-  RtreeMatchArg *pBlob, *pSrc;       /* BLOB returned by geometry function */
-  sqlite3_rtree_query_info *pInfo;   /* Callback information */
-
-  pSrc = sqlite3_value_pointer(pValue, "RtreeMatchArg");
-  if( pSrc==0 ) return SQLITE_ERROR;
-  pInfo = (sqlite3_rtree_query_info*)
-                sqlite3_malloc64( sizeof(*pInfo)+pSrc->iSize );
-  if( !pInfo ) return SQLITE_NOMEM;
-  memset(pInfo, 0, sizeof(*pInfo));
-  pBlob = (RtreeMatchArg*)&pInfo[1];
-  memcpy(pBlob, pSrc, pSrc->iSize);
-  pInfo->pContext = pBlob->cb.pContext;
-  pInfo->nParam = pBlob->nParam;
-  pInfo->aParam = pBlob->aParam;
-  pInfo->apSqlParam = pBlob->apSqlParam;
+static void jsonReplaceFunc(
+  sqlite3_context *ctx,
+  int argc,
+  sqlite3_value **argv
+){
+  JsonParse x;          /* The parse */
+  JsonNode *pNode;
+  const char *zPath;
+  u32 i;
 
-  if( pBlob->cb.xGeom ){
-    pCons->u.xGeom = pBlob->cb.xGeom;
+  if( argc<1 ) return;
+  if( (argc&1)==0 ) {
+    jsonWrongNumArgs(ctx, "replace");
+    return;
+  }
+  if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
+  assert( x.nNode );
+  for(i=1; i<(u32)argc; i+=2){
+    zPath = (const char*)sqlite3_value_text(argv[i]);
+    pNode = jsonLookup(&x, zPath, 0, ctx);
+    if( x.nErr ) goto replace_err;
+    if( pNode ){
+      pNode->jnFlags |= (u8)JNODE_REPLACE;
+      pNode->u.iReplace = i + 1;
+    }
+  }
+  if( x.aNode[0].jnFlags & JNODE_REPLACE ){
+    sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
   }else{
-    pCons->op = RTREE_QUERY;
-    pCons->u.xQueryFunc = pBlob->cb.xQueryFunc;
+    jsonReturnJson(x.aNode, ctx, argv);
   }
-  pCons->pInfo = pInfo;
-  return SQLITE_OK;
+replace_err:
+  jsonParseReset(&x);
 }
 
-/* 
-** Rtree virtual table module xFilter method.
+/*
+** json_set(JSON, PATH, VALUE, ...)
+**
+** Set the value at PATH to VALUE.  Create the PATH if it does not already
+** exist.  Overwrite existing values that do exist.
+** If JSON or PATH is malformed, throw an error.
+**
+** json_insert(JSON, PATH, VALUE, ...)
+**
+** Create PATH and initialize it to VALUE.  If PATH already exists, this
+** routine is a no-op.  If JSON or PATH is malformed, throw an error.
 */
-static int rtreeFilter(
-  sqlite3_vtab_cursor *pVtabCursor, 
-  int idxNum, const char *idxStr,
-  int argc, sqlite3_value **argv
+static void jsonSetFunc(
+  sqlite3_context *ctx,
+  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;
-  sqlite3_stmt *pStmt;
-
-  rtreeReference(pRtree);
-
-  /* Reset the cursor to the same state as rtreeOpen() leaves it in. */
-  freeCursorConstraints(pCsr);
-  sqlite3_free(pCsr->aPoint);
-  pStmt = pCsr->pReadAux;
-  memset(pCsr, 0, sizeof(RtreeCursor));
-  pCsr->base.pVtab = (sqlite3_vtab*)pRtree;
-  pCsr->pReadAux = pStmt;
+  JsonParse x;          /* The parse */
+  JsonNode *pNode;
+  const char *zPath;
+  u32 i;
+  int bApnd;
+  int bIsSet = *(int*)sqlite3_user_data(ctx);
 
-  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;
+  if( argc<1 ) return;
+  if( (argc&1)==0 ) {
+    jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert");
+    return;
+  }
+  if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
+  assert( x.nNode );
+  for(i=1; i<(u32)argc; i+=2){
+    zPath = (const char*)sqlite3_value_text(argv[i]);
+    bApnd = 0;
+    pNode = jsonLookup(&x, zPath, &bApnd, ctx);
+    if( x.oom ){
+      sqlite3_result_error_nomem(ctx);
+      goto jsonSetDone;
+    }else if( x.nErr ){
+      goto jsonSetDone;
+    }else if( pNode && (bApnd || bIsSet) ){
+      pNode->jnFlags |= (u8)JNODE_REPLACE;
+      pNode->u.iReplace = i + 1;
     }
+  }
+  if( x.aNode[0].jnFlags & JNODE_REPLACE ){
+    sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
   }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; ii<argc; ii++){
-          RtreeConstraint *p = &pCsr->aConstraint[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);
-    }
+    jsonReturnJson(x.aNode, ctx, argv);
   }
-
-  nodeRelease(pRtree, pRoot);
-  rtreeRelease(pRtree);
-  return rc;
+jsonSetDone:
+  jsonParseReset(&x);
 }
 
 /*
-** 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')
-**   ----------------------
+** json_type(JSON)
+** json_type(JSON, PATH)
 **
-** 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.
+** Return the top-level "type" of a JSON string.  Throw an error if
+** either the JSON or PATH inputs are not well-formed.
 */
-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; ii<pIdxInfo->nConstraint; ii++){
-    if( pIdxInfo->aConstraint[ii].op==SQLITE_INDEX_CONSTRAINT_MATCH ){
-      bMatch = 1;
-    }
-  }
-
-  assert( pIdxInfo->idxStr==0 );
-  for(ii=0; ii<pIdxInfo->nConstraint && iIdx<(int)(sizeof(zIdxStr)-1); ii++){
-    struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];
-
-    if( bMatch==0 && p->usable 
-     && p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ 
-    ){
-      /* We have an equality constraint on the rowid. Use strategy 1. */
-      int jj;
-      for(jj=0; jj<ii; jj++){
-        pIdxInfo->aConstraintUsage[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;
-      pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
-      return SQLITE_OK;
-    }
+static void jsonTypeFunc(
+  sqlite3_context *ctx,
+  int argc,
+  sqlite3_value **argv
+){
+  JsonParse *p;          /* The parse */
+  const char *zPath;
+  JsonNode *pNode;
 
-    if( p->usable
-    && ((p->iColumn>0 && p->iColumn<=pRtree->nDim2)
-        || 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;
-    }
+  p = jsonParseCached(ctx, argv, ctx);
+  if( p==0 ) return;
+  if( argc==2 ){
+    zPath = (const char*)sqlite3_value_text(argv[1]);
+    pNode = jsonLookup(p, zPath, 0, ctx);
+  }else{
+    pNode = p->aNode;
   }
-
-  pIdxInfo->idxNum = 2;
-  pIdxInfo->needToFreeIdxStr = 1;
-  if( iIdx>0 && 0==(pIdxInfo->idxStr = sqlite3_mprintf("%s", zIdxStr)) ){
-    return SQLITE_NOMEM;
+  if( pNode ){
+    sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC);
   }
-
-  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.
+** json_valid(JSON)
+**
+** Return 1 if JSON is a well-formed JSON string according to RFC-7159.
+** Return 0 otherwise.
 */
-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;
+static void jsonValidFunc(
+  sqlite3_context *ctx,
+  int argc,
+  sqlite3_value **argv
+){
+  JsonParse *p;          /* The parse */
+  UNUSED_PARAM(argc);
+  p = jsonParseCached(ctx, argv, 0);
+  sqlite3_result_int(ctx, p!=0);
 }
 
-/*
-** 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;
-}
 
+/****************************************************************************
+** Aggregate SQL function implementations
+****************************************************************************/
 /*
-** Store the union of cells p1 and p2 in p1.
+** json_group_array(VALUE)
+**
+** Return a JSON array composed of all values in the aggregate.
 */
-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( ii<pRtree->nDim2 );
-  }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( ii<pRtree->nDim2 );
+static void jsonArrayStep(
+  sqlite3_context *ctx,
+  int argc,
+  sqlite3_value **argv
+){
+  JsonString *pStr;
+  UNUSED_PARAM(argc);
+  pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
+  if( pStr ){
+    if( pStr->zBuf==0 ){
+      jsonInit(pStr, ctx);
+      jsonAppendChar(pStr, '[');
+    }else{
+      jsonAppendChar(pStr, ',');
+      pStr->pCtx = ctx;
+    }
+    jsonAppendValue(pStr, argv[0]);
   }
 }
-
-/*
-** 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; ii<pRtree->nDim2; ii+=2){
-    RtreeCoord *a1 = &p1->aCoord[ii];
-    RtreeCoord *a2 = &p2->aCoord[ii];
-    if( (!isInt && (a2[0].f<a1[0].f || a2[1].f>a1[1].f)) 
-     || ( isInt && (a2[0].i<a1[0].i || a2[1].i>a1[1].i)) 
-    ){
-      return 0;
+static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){
+  JsonString *pStr;
+  pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
+  if( pStr ){
+    pStr->pCtx = ctx;
+    jsonAppendChar(pStr, ']');
+    if( pStr->bErr ){
+      if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
+      assert( pStr->bStatic );
+    }else if( isFinal ){
+      sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed,
+                          pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
+      pStr->bStatic = 1;
+    }else{
+      sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT);
+      pStr->nUsed--;
     }
+  }else{
+    sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC);
   }
-  return 1;
+  sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+}
+static void jsonArrayValue(sqlite3_context *ctx){
+  jsonArrayCompute(ctx, 0);
+}
+static void jsonArrayFinal(sqlite3_context *ctx){
+  jsonArrayCompute(ctx, 1);
 }
 
+#ifndef SQLITE_OMIT_WINDOWFUNC
 /*
-** Return the amount cell p would grow by if it were unioned with pCell.
+** This method works for both json_group_array() and json_group_object().
+** It works by removing the first element of the group by searching forward
+** to the first comma (",") that is not within a string and deleting all
+** text through that comma.
 */
-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
+static void jsonGroupInverse(
+  sqlite3_context *ctx,
+  int argc,
+  sqlite3_value **argv
 ){
-  int ii;
-  RtreeDValue overlap = RTREE_ZERO;
-  for(ii=0; ii<nCell; ii++){
-    int jj;
-    RtreeDValue o = (RtreeDValue)1;
-    for(jj=0; jj<pRtree->nDim2; 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( x2<x1 ){
-        o = (RtreeDValue)0;
-        break;
-      }else{
-        o = o * (x2-x1);
-      }
+  int i;
+  int inStr = 0;
+  char *z;
+  JsonString *pStr;
+  UNUSED_PARAM(argc);
+  UNUSED_PARAM(argv);
+  pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
+#ifdef NEVER
+  /* pStr is always non-NULL since jsonArrayStep() or jsonObjectStep() will
+  ** always have been called to initalize it */
+  if( NEVER(!pStr) ) return;
+#endif
+  z = pStr->zBuf;
+  for(i=1; z[i]!=',' || inStr; i++){
+    assert( i<pStr->nUsed );
+    if( z[i]=='"' ){
+      inStr = !inStr;
+    }else if( z[i]=='\\' ){
+      i++;
     }
-    overlap += o;
   }
-  return overlap;
+  pStr->nUsed -= i;      
+  memmove(&z[1], &z[i+1], (size_t)pStr->nUsed-1);
 }
+#else
+# define jsonGroupInverse 0
+#endif
 
 
 /*
-** This function implements the ChooseLeaf algorithm from Gutman[84].
-** ChooseSubTree in r*tree terminology.
+** json_group_obj(NAME,VALUE)
+**
+** Return a JSON object composed of all names and values in the aggregate.
 */
-static int ChooseLeaf(
-  Rtree *pRtree,               /* Rtree table */
-  RtreeCell *pCell,            /* Cell to insert into rtree */
-  int iHeight,                 /* Height of sub-tree rooted at pCell */
-  RtreeNode **ppLeaf           /* OUT: Selected leaf page */
+static void jsonObjectStep(
+  sqlite3_context *ctx,
+  int argc,
+  sqlite3_value **argv
 ){
-  int rc;
-  int ii;
-  RtreeNode *pNode = 0;
-  rc = nodeAcquire(pRtree, 1, 0, &pNode);
+  JsonString *pStr;
+  const char *z;
+  u32 n;
+  UNUSED_PARAM(argc);
+  pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
+  if( pStr ){
+    if( pStr->zBuf==0 ){
+      jsonInit(pStr, ctx);
+      jsonAppendChar(pStr, '{');
+    }else{
+      jsonAppendChar(pStr, ',');
+      pStr->pCtx = ctx;
+    }
+    z = (const char*)sqlite3_value_text(argv[0]);
+    n = (u32)sqlite3_value_bytes(argv[0]);
+    jsonAppendString(pStr, z, n);
+    jsonAppendChar(pStr, ':');
+    jsonAppendValue(pStr, argv[1]);
+  }
+}
+static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){
+  JsonString *pStr;
+  pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
+  if( pStr ){
+    jsonAppendChar(pStr, '}');
+    if( pStr->bErr ){
+      if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
+      assert( pStr->bStatic );
+    }else if( isFinal ){
+      sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed,
+                          pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
+      pStr->bStatic = 1;
+    }else{
+      sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT);
+      pStr->nUsed--;
+    }
+  }else{
+    sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC);
+  }
+  sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+}
+static void jsonObjectValue(sqlite3_context *ctx){
+  jsonObjectCompute(ctx, 0);
+}
+static void jsonObjectFinal(sqlite3_context *ctx){
+  jsonObjectCompute(ctx, 1);
+}
 
-  for(ii=0; rc==SQLITE_OK && ii<(pRtree->iDepth-iHeight); ii++){
-    int iCell;
-    sqlite3_int64 iBest = 0;
 
-    RtreeDValue fMinGrowth = RTREE_ZERO;
-    RtreeDValue fMinArea = RTREE_ZERO;
 
-    int nCell = NCELL(pNode);
-    RtreeCell cell;
-    RtreeNode *pChild;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/****************************************************************************
+** The json_each virtual table
+****************************************************************************/
+typedef struct JsonEachCursor JsonEachCursor;
+struct JsonEachCursor {
+  sqlite3_vtab_cursor base;  /* Base class - must be first */
+  u32 iRowid;                /* The rowid */
+  u32 iBegin;                /* The first node of the scan */
+  u32 i;                     /* Index in sParse.aNode[] of current row */
+  u32 iEnd;                  /* EOF when i equals or exceeds this value */
+  u8 eType;                  /* Type of top-level element */
+  u8 bRecursive;             /* True for json_tree().  False for json_each() */
+  char *zJson;               /* Input JSON */
+  char *zRoot;               /* Path by which to filter zJson */
+  JsonParse sParse;          /* Parse of the input JSON */
+};
 
-    RtreeCell *aCell = 0;
+/* Constructor for the json_each virtual table */
+static int jsonEachConnect(
+  sqlite3 *db,
+  void *pAux,
+  int argc, const char *const*argv,
+  sqlite3_vtab **ppVtab,
+  char **pzErr
+){
+  sqlite3_vtab *pNew;
+  int rc;
 
-    /* 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; iCell<nCell; iCell++){
-      int bBest = 0;
-      RtreeDValue growth;
-      RtreeDValue area;
-      nodeGetCell(pRtree, pNode, iCell, &cell);
-      growth = cellGrowth(pRtree, &cell, pCell);
-      area = cellArea(pRtree, &cell);
-      if( iCell==0||growth<fMinGrowth||(growth==fMinGrowth && area<fMinArea) ){
-        bBest = 1;
-      }
-      if( bBest ){
-        fMinGrowth = growth;
-        fMinArea = area;
-        iBest = cell.iRowid;
-      }
-    }
+/* Column numbers */
+#define JEACH_KEY     0
+#define JEACH_VALUE   1
+#define JEACH_TYPE    2
+#define JEACH_ATOM    3
+#define JEACH_ID      4
+#define JEACH_PARENT  5
+#define JEACH_FULLKEY 6
+#define JEACH_PATH    7
+#define JEACH_JSON    8
+#define JEACH_ROOT    9
 
-    sqlite3_free(aCell);
-    rc = nodeAcquire(pRtree, iBest, pNode, &pChild);
-    nodeRelease(pRtree, pNode);
-    pNode = pChild;
+  UNUSED_PARAM(pzErr);
+  UNUSED_PARAM(argv);
+  UNUSED_PARAM(argc);
+  UNUSED_PARAM(pAux);
+  rc = sqlite3_declare_vtab(db, 
+     "CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path,"
+                    "json HIDDEN,root HIDDEN)");
+  if( rc==SQLITE_OK ){
+    pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
+    if( pNew==0 ) return SQLITE_NOMEM;
+    memset(pNew, 0, sizeof(*pNew));
   }
-
-  *ppLeaf = pNode;
   return rc;
 }
 
-/*
-** A cell with the same content as pCell has just been inserted into
-** the node pNode. This function updates the bounding box cells in
-** all ancestor elements.
-*/
-static int AdjustTree(
-  Rtree *pRtree,                    /* Rtree table */
-  RtreeNode *pNode,                 /* Adjust ancestry of this node. */
-  RtreeCell *pCell                  /* This cell was just inserted */
-){
-  RtreeNode *p = pNode;
-  while( p->pParent ){
-    RtreeNode *pParent = p->pParent;
-    RtreeCell cell;
-    int iCell;
+/* destructor for json_each virtual table */
+static int jsonEachDisconnect(sqlite3_vtab *pVtab){
+  sqlite3_free(pVtab);
+  return SQLITE_OK;
+}
 
-    if( nodeParentIndex(pRtree, p, &iCell) ){
-      return SQLITE_CORRUPT_VTAB;
-    }
+/* constructor for a JsonEachCursor object for json_each(). */
+static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+  JsonEachCursor *pCur;
 
-    nodeGetCell(pRtree, pParent, iCell, &cell);
-    if( !cellContains(pRtree, &cell, pCell) ){
-      cellUnion(pRtree, &cell, pCell);
-      nodeOverwriteCell(pRtree, pParent, &cell, iCell);
-    }
-    p = pParent;
-  }
+  UNUSED_PARAM(p);
+  pCur = sqlite3_malloc( sizeof(*pCur) );
+  if( pCur==0 ) return SQLITE_NOMEM;
+  memset(pCur, 0, sizeof(*pCur));
+  *ppCursor = &pCur->base;
   return SQLITE_OK;
 }
 
-/*
-** Write mapping (iRowid->iNode) to the <rtree>_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);
+/* constructor for a JsonEachCursor object for json_tree(). */
+static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+  int rc = jsonEachOpenEach(p, ppCursor);
+  if( rc==SQLITE_OK ){
+    JsonEachCursor *pCur = (JsonEachCursor*)*ppCursor;
+    pCur->bRecursive = 1;
+  }
+  return rc;
 }
 
-/*
-** Write mapping (iNode->iPar) to the <rtree>_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);
+/* Reset a JsonEachCursor back to its original state.  Free any memory
+** held. */
+static void jsonEachCursorReset(JsonEachCursor *p){
+  sqlite3_free(p->zJson);
+  sqlite3_free(p->zRoot);
+  jsonParseReset(&p->sParse);
+  p->iRowid = 0;
+  p->i = 0;
+  p->iEnd = 0;
+  p->eType = 0;
+  p->zJson = 0;
+  p->zRoot = 0;
 }
 
-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);
+/* Destructor for a jsonEachCursor object */
+static int jsonEachClose(sqlite3_vtab_cursor *cur){
+  JsonEachCursor *p = (JsonEachCursor*)cur;
+  jsonEachCursorReset(p);
+  sqlite3_free(cur);
+  return SQLITE_OK;
+}
 
-    memcpy(aSpare, aLeft, sizeof(int)*nLeft);
-    aLeft = aSpare;
+/* Return TRUE if the jsonEachCursor object has been advanced off the end
+** of the JSON object */
+static int jsonEachEof(sqlite3_vtab_cursor *cur){
+  JsonEachCursor *p = (JsonEachCursor*)cur;
+  return p->i >= p->iEnd;
+}
 
-    while( iLeft<nLeft || iRight<nRight ){
-      if( iLeft==nLeft ){
-        aIdx[iLeft+iRight] = aRight[iRight];
-        iRight++;
-      }else if( iRight==nRight ){
-        aIdx[iLeft+iRight] = aLeft[iLeft];
-        iLeft++;
-      }else{
-        RtreeDValue fLeft = aDistance[aLeft[iLeft]];
-        RtreeDValue fRight = aDistance[aRight[iRight]];
-        if( fLeft<fRight ){
-          aIdx[iLeft+iRight] = aLeft[iLeft];
-          iLeft++;
+/* Advance the cursor to the next element for json_tree() */
+static int jsonEachNext(sqlite3_vtab_cursor *cur){
+  JsonEachCursor *p = (JsonEachCursor*)cur;
+  if( p->bRecursive ){
+    if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++;
+    p->i++;
+    p->iRowid++;
+    if( p->i<p->iEnd ){
+      u32 iUp = p->sParse.aUp[p->i];
+      JsonNode *pUp = &p->sParse.aNode[iUp];
+      p->eType = pUp->eType;
+      if( pUp->eType==JSON_ARRAY ){
+        if( iUp==p->i-1 ){
+          pUp->u.iKey = 0;
         }else{
-          aIdx[iLeft+iRight] = aRight[iRight];
-          iRight++;
+          pUp->u.iKey++;
         }
       }
     }
-
-#if 0
-    /* Check that the sort worked */
-    {
-      int jj;
-      for(jj=1; jj<nIdx; jj++){
-        RtreeDValue left = aDistance[aIdx[jj-1]];
-        RtreeDValue right = aDistance[aIdx[jj]];
-        assert( left<=right );
+  }else{
+    switch( p->eType ){
+      case JSON_ARRAY: {
+        p->i += jsonNodeSize(&p->sParse.aNode[p->i]);
+        p->iRowid++;
+        break;
       }
-    }
-#endif
-  }
-}
-
-/*
-** Arguments aIdx, aCell 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 dimension iDim of the cells in aCell. The
-** minimum value of dimension iDim is considered first, the
-** maximum used to break ties.
-**
-** The aSpare array is used as temporary working space by the
-** sorting algorithm.
-*/
-static void SortByDimension(
-  Rtree *pRtree,
-  int *aIdx, 
-  int nIdx, 
-  int iDim, 
-  RtreeCell *aCell, 
-  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];
-
-    SortByDimension(pRtree, aLeft, nLeft, iDim, aCell, aSpare);
-    SortByDimension(pRtree, aRight, nRight, iDim, aCell, aSpare);
-
-    memcpy(aSpare, aLeft, sizeof(int)*nLeft);
-    aLeft = aSpare;
-    while( iLeft<nLeft || iRight<nRight ){
-      RtreeDValue xleft1 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2]);
-      RtreeDValue xleft2 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2+1]);
-      RtreeDValue xright1 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2]);
-      RtreeDValue xright2 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2+1]);
-      if( (iLeft!=nLeft) && ((iRight==nRight)
-       || (xleft1<xright1)
-       || (xleft1==xright1 && xleft2<xright2)
-      )){
-        aIdx[iLeft+iRight] = aLeft[iLeft];
-        iLeft++;
-      }else{
-        aIdx[iLeft+iRight] = aRight[iRight];
-        iRight++;
+      case JSON_OBJECT: {
+        p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]);
+        p->iRowid++;
+        break;
       }
-    }
-
-#if 0
-    /* Check that the sort worked */
-    {
-      int jj;
-      for(jj=1; jj<nIdx; jj++){
-        RtreeDValue xleft1 = aCell[aIdx[jj-1]].aCoord[iDim*2];
-        RtreeDValue xleft2 = aCell[aIdx[jj-1]].aCoord[iDim*2+1];
-        RtreeDValue xright1 = aCell[aIdx[jj]].aCoord[iDim*2];
-        RtreeDValue xright2 = aCell[aIdx[jj]].aCoord[iDim*2+1];
-        assert( xleft1<=xright1 && (xleft1<xright1 || xleft2<=xright2) );
+      default: {
+        p->i = p->iEnd;
+        break;
       }
     }
-#endif
   }
+  return SQLITE_OK;
 }
 
-/*
-** Implementation of the R*-tree variant of SplitNode from Beckman[1990].
+/* Append the name of the path for element i to pStr
 */
-static int splitNodeStartree(
-  Rtree *pRtree,
-  RtreeCell *aCell,
-  int nCell,
-  RtreeNode *pLeft,
-  RtreeNode *pRight,
-  RtreeCell *pBboxLeft,
-  RtreeCell *pBboxRight
+static void jsonEachComputePath(
+  JsonEachCursor *p,       /* The cursor */
+  JsonString *pStr,        /* Write the path here */
+  u32 i                    /* Path to this element */
 ){
-  int **aaSorted;
-  int *aSpare;
-  int ii;
-
-  int iBestDim = 0;
-  int iBestSplit = 0;
-  RtreeDValue fBestMargin = RTREE_ZERO;
-
-  int nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int));
-
-  aaSorted = (int **)sqlite3_malloc(nByte);
-  if( !aaSorted ){
-    return SQLITE_NOMEM;
+  JsonNode *pNode, *pUp;
+  u32 iUp;
+  if( i==0 ){
+    jsonAppendChar(pStr, '$');
+    return;
   }
-
-  aSpare = &((int *)&aaSorted[pRtree->nDim])[pRtree->nDim*nCell];
-  memset(aaSorted, 0, nByte);
-  for(ii=0; ii<pRtree->nDim; ii++){
-    int jj;
-    aaSorted[ii] = &((int *)&aaSorted[pRtree->nDim])[ii*nCell];
-    for(jj=0; jj<nCell; jj++){
-      aaSorted[ii][jj] = jj;
-    }
-    SortByDimension(pRtree, aaSorted[ii], nCell, ii, aCell, aSpare);
+  iUp = p->sParse.aUp[i];
+  jsonEachComputePath(p, pStr, iUp);
+  pNode = &p->sParse.aNode[i];
+  pUp = &p->sParse.aNode[iUp];
+  if( pUp->eType==JSON_ARRAY ){
+    jsonPrintf(30, pStr, "[%d]", pUp->u.iKey);
+  }else{
+    assert( pUp->eType==JSON_OBJECT );
+    if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--;
+    assert( pNode->eType==JSON_STRING );
+    assert( pNode->jnFlags & JNODE_LABEL );
+    jsonPrintf(pNode->n+1, pStr, ".%.*s", pNode->n-2, pNode->u.zJContent+1);
   }
+}
 
-  for(ii=0; ii<pRtree->nDim; 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( kk<nLeft ){
-          cellUnion(pRtree, &left, &aCell[aaSorted[ii][kk]]);
+/* Return the value of a column */
+static int jsonEachColumn(
+  sqlite3_vtab_cursor *cur,   /* The cursor */
+  sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
+  int i                       /* Which column to return */
+){
+  JsonEachCursor *p = (JsonEachCursor*)cur;
+  JsonNode *pThis = &p->sParse.aNode[p->i];
+  switch( i ){
+    case JEACH_KEY: {
+      if( p->i==0 ) break;
+      if( p->eType==JSON_OBJECT ){
+        jsonReturn(pThis, ctx, 0);
+      }else if( p->eType==JSON_ARRAY ){
+        u32 iKey;
+        if( p->bRecursive ){
+          if( p->iRowid==0 ) break;
+          iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey;
         }else{
-          cellUnion(pRtree, &right, &aCell[aaSorted[ii][kk]]);
+          iKey = p->iRowid;
         }
+        sqlite3_result_int64(ctx, (sqlite3_int64)iKey);
       }
-      margin += cellMargin(pRtree, &left);
-      margin += cellMargin(pRtree, &right);
-      overlap = cellOverlap(pRtree, &left, &right, 1);
-      area = cellArea(pRtree, &left) + cellArea(pRtree, &right);
-      if( (nLeft==RTREE_MINCELLS(pRtree))
-       || (overlap<fBestOverlap)
-       || (overlap==fBestOverlap && area<fBestArea)
-      ){
-        iBestLeft = nLeft;
-        fBestOverlap = overlap;
-        fBestArea = area;
+      break;
+    }
+    case JEACH_VALUE: {
+      if( pThis->jnFlags & JNODE_LABEL ) pThis++;
+      jsonReturn(pThis, ctx, 0);
+      break;
+    }
+    case JEACH_TYPE: {
+      if( pThis->jnFlags & JNODE_LABEL ) pThis++;
+      sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC);
+      break;
+    }
+    case JEACH_ATOM: {
+      if( pThis->jnFlags & JNODE_LABEL ) pThis++;
+      if( pThis->eType>=JSON_ARRAY ) break;
+      jsonReturn(pThis, ctx, 0);
+      break;
+    }
+    case JEACH_ID: {
+      sqlite3_result_int64(ctx, 
+         (sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0));
+      break;
+    }
+    case JEACH_PARENT: {
+      if( p->i>p->iBegin && p->bRecursive ){
+        sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]);
       }
+      break;
     }
-
-    if( ii==0 || margin<fBestMargin ){
-      iBestDim = ii;
-      fBestMargin = margin;
-      iBestSplit = iBestLeft;
+    case JEACH_FULLKEY: {
+      JsonString x;
+      jsonInit(&x, ctx);
+      if( p->bRecursive ){
+        jsonEachComputePath(p, &x, p->i);
+      }else{
+        if( p->zRoot ){
+          jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot));
+        }else{
+          jsonAppendChar(&x, '$');
+        }
+        if( p->eType==JSON_ARRAY ){
+          jsonPrintf(30, &x, "[%d]", p->iRowid);
+        }else if( p->eType==JSON_OBJECT ){
+          jsonPrintf(pThis->n, &x, ".%.*s", pThis->n-2, pThis->u.zJContent+1);
+        }
+      }
+      jsonResult(&x);
+      break;
+    }
+    case JEACH_PATH: {
+      if( p->bRecursive ){
+        JsonString x;
+        jsonInit(&x, ctx);
+        jsonEachComputePath(p, &x, p->sParse.aUp[p->i]);
+        jsonResult(&x);
+        break;
+      }
+      /* For json_each() path and root are the same so fall through
+      ** into the root case */
+    }
+    default: {
+      const char *zRoot = p->zRoot;
+      if( zRoot==0 ) zRoot = "$";
+      sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
+      break;
+    }
+    case JEACH_JSON: {
+      assert( i==JEACH_JSON );
+      sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC);
+      break;
     }
   }
-
-  memcpy(pBboxLeft, &aCell[aaSorted[iBestDim][0]], sizeof(RtreeCell));
-  memcpy(pBboxRight, &aCell[aaSorted[iBestDim][iBestSplit]], sizeof(RtreeCell));
-  for(ii=0; ii<nCell; ii++){
-    RtreeNode *pTarget = (ii<iBestSplit)?pLeft:pRight;
-    RtreeCell *pBbox = (ii<iBestSplit)?pBboxLeft:pBboxRight;
-    RtreeCell *pCell = &aCell[aaSorted[iBestDim][ii]];
-    nodeInsertCell(pRtree, pTarget, pCell);
-    cellUnion(pRtree, pBbox, pCell);
-  }
-
-  sqlite3_free(aaSorted);
   return SQLITE_OK;
 }
 
-
-static int updateMapping(
-  Rtree *pRtree, 
-  i64 iRowid, 
-  RtreeNode *pNode, 
-  int iHeight
-){
-  int (*xSetMapping)(Rtree *, sqlite3_int64, sqlite3_int64);
-  xSetMapping = ((iHeight==0)?rowidWrite:parentWrite);
-  if( iHeight>0 ){
-    RtreeNode *pChild = nodeHashLookup(pRtree, iRowid);
-    if( pChild ){
-      nodeRelease(pRtree, pChild->pParent);
-      nodeReference(pNode);
-      pChild->pParent = pNode;
-    }
-  }
-  return xSetMapping(pRtree, iRowid, pNode->iNode);
+/* Return the current rowid value */
+static int jsonEachRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+  JsonEachCursor *p = (JsonEachCursor*)cur;
+  *pRowid = p->iRowid;
+  return SQLITE_OK;
 }
 
-static int SplitNode(
-  Rtree *pRtree,
-  RtreeNode *pNode,
-  RtreeCell *pCell,
-  int iHeight
+/* The query strategy is to look for an equality constraint on the json
+** column.  Without such a constraint, the table cannot operate.  idxNum is
+** 1 if the constraint is found, 3 if the constraint and zRoot are found,
+** and 0 otherwise.
+*/
+static int jsonEachBestIndex(
+  sqlite3_vtab *tab,
+  sqlite3_index_info *pIdxInfo
 ){
   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;
+  int jsonIdx = -1;
+  int rootIdx = -1;
+  const struct sqlite3_index_constraint *pConstraint;
 
-  /* 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; i<nCell; i++){
-    nodeGetCell(pRtree, pNode, i, &aCell[i]);
+  UNUSED_PARAM(tab);
+  pConstraint = pIdxInfo->aConstraint;
+  for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
+    if( pConstraint->usable==0 ) continue;
+    if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
+    switch( pConstraint->iColumn ){
+      case JEACH_JSON:   jsonIdx = i;    break;
+      case JEACH_ROOT:   rootIdx = i;    break;
+      default:           /* no-op */     break;
+    }
   }
-  nodeZero(pRtree, pNode);
-  memcpy(&aCell[nCell], pCell, sizeof(RtreeCell));
-  nCell++;
-
-  if( pNode->iNode==1 ){
-    pRight = nodeNew(pRtree, pNode);
-    pLeft = nodeNew(pRtree, pNode);
-    pRtree->iDepth++;
-    pNode->isDirty = 1;
-    writeInt16(pNode->zData, pRtree->iDepth);
+  if( jsonIdx<0 ){
+    pIdxInfo->idxNum = 0;
+    pIdxInfo->estimatedCost = 1e99;
   }else{
-    pLeft = pNode;
-    pRight = nodeNew(pRtree, pLeft->pParent);
-    pLeft->nRef++;
-  }
-
-  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;
+    pIdxInfo->estimatedCost = 1.0;
+    pIdxInfo->aConstraintUsage[jsonIdx].argvIndex = 1;
+    pIdxInfo->aConstraintUsage[jsonIdx].omit = 1;
+    if( rootIdx<0 ){
+      pIdxInfo->idxNum = 1;
+    }else{
+      pIdxInfo->aConstraintUsage[rootIdx].argvIndex = 2;
+      pIdxInfo->aConstraintUsage[rootIdx].omit = 1;
+      pIdxInfo->idxNum = 3;
+    }
   }
+  return SQLITE_OK;
+}
 
-  rightbbox.iRowid = pRight->iNode;
-  leftbbox.iRowid = pLeft->iNode;
+/* Start a search on a new JSON string */
+static int jsonEachFilter(
+  sqlite3_vtab_cursor *cur,
+  int idxNum, const char *idxStr,
+  int argc, sqlite3_value **argv
+){
+  JsonEachCursor *p = (JsonEachCursor*)cur;
+  const char *z;
+  const char *zRoot = 0;
+  sqlite3_int64 n;
 
-  if( pNode->iNode==1 ){
-    rc = rtreeInsertCell(pRtree, pLeft->pParent, &leftbbox, iHeight+1);
-    if( rc!=SQLITE_OK ){
-      goto splitnode_out;
+  UNUSED_PARAM(idxStr);
+  UNUSED_PARAM(argc);
+  jsonEachCursorReset(p);
+  if( idxNum==0 ) return SQLITE_OK;
+  z = (const char*)sqlite3_value_text(argv[0]);
+  if( z==0 ) return SQLITE_OK;
+  n = sqlite3_value_bytes(argv[0]);
+  p->zJson = sqlite3_malloc64( n+1 );
+  if( p->zJson==0 ) return SQLITE_NOMEM;
+  memcpy(p->zJson, z, (size_t)n+1);
+  if( jsonParse(&p->sParse, 0, p->zJson) ){
+    int rc = SQLITE_NOMEM;
+    if( p->sParse.oom==0 ){
+      sqlite3_free(cur->pVtab->zErrMsg);
+      cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON");
+      if( cur->pVtab->zErrMsg ) rc = SQLITE_ERROR;
     }
+    jsonEachCursorReset(p);
+    return rc;
+  }else if( p->bRecursive && jsonParseFindParents(&p->sParse) ){
+    jsonEachCursorReset(p);
+    return SQLITE_NOMEM;
   }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; i<NCELL(pRight); i++){
-    i64 iRowid = nodeGetRowid(pRtree, pRight, i);
-    rc = updateMapping(pRtree, iRowid, pRight, iHeight);
-    if( iRowid==pCell->iRowid ){
-      newCellIsRight = 1;
-    }
-    if( rc!=SQLITE_OK ){
-      goto splitnode_out;
-    }
-  }
-  if( pNode->iNode==1 ){
-    for(i=0; i<NCELL(pLeft); i++){
-      i64 iRowid = nodeGetRowid(pRtree, pLeft, i);
-      rc = updateMapping(pRtree, iRowid, pLeft, iHeight);
-      if( rc!=SQLITE_OK ){
-        goto splitnode_out;
+    JsonNode *pNode = 0;
+    if( idxNum==3 ){
+      const char *zErr = 0;
+      zRoot = (const char*)sqlite3_value_text(argv[1]);
+      if( zRoot==0 ) return SQLITE_OK;
+      n = sqlite3_value_bytes(argv[1]);
+      p->zRoot = sqlite3_malloc64( n+1 );
+      if( p->zRoot==0 ) return SQLITE_NOMEM;
+      memcpy(p->zRoot, zRoot, (size_t)n+1);
+      if( zRoot[0]!='$' ){
+        zErr = zRoot;
+      }else{
+        pNode = jsonLookupStep(&p->sParse, 0, p->zRoot+1, 0, &zErr);
+      }
+      if( zErr ){
+        sqlite3_free(cur->pVtab->zErrMsg);
+        cur->pVtab->zErrMsg = jsonPathSyntaxError(zErr);
+        jsonEachCursorReset(p);
+        return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
+      }else if( pNode==0 ){
+        return SQLITE_OK;
       }
+    }else{
+      pNode = p->sParse.aNode;
     }
-  }else if( newCellIsRight==0 ){
-    rc = updateMapping(pRtree, pCell->iRowid, 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);
+    p->iBegin = p->i = (int)(pNode - p->sParse.aNode);
+    p->eType = pNode->eType;
+    if( p->eType>=JSON_ARRAY ){
+      pNode->u.iKey = 0;
+      p->iEnd = p->i + pNode->n + 1;
+      if( p->bRecursive ){
+        p->eType = p->sParse.aNode[p->sParse.aUp[p->i]].eType;
+        if( p->i>0 && (p->sParse.aNode[p->i-1].jnFlags & JNODE_LABEL)!=0 ){
+          p->i--;
+        }
+      }else{
+        p->i++;
       }
+    }else{
+      p->iEnd = p->i+1;
     }
-    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;
+  return SQLITE_OK;
 }
 
-static int deleteCell(Rtree *, RtreeNode *, int, int);
+/* The methods of the json_each virtual table */
+static sqlite3_module jsonEachModule = {
+  0,                         /* iVersion */
+  0,                         /* xCreate */
+  jsonEachConnect,           /* xConnect */
+  jsonEachBestIndex,         /* xBestIndex */
+  jsonEachDisconnect,        /* xDisconnect */
+  0,                         /* xDestroy */
+  jsonEachOpenEach,          /* xOpen - open a cursor */
+  jsonEachClose,             /* xClose - close a cursor */
+  jsonEachFilter,            /* xFilter - configure scan constraints */
+  jsonEachNext,              /* xNext - advance a cursor */
+  jsonEachEof,               /* xEof - check for end of scan */
+  jsonEachColumn,            /* xColumn - read data */
+  jsonEachRowid,             /* xRowid - read data */
+  0,                         /* xUpdate */
+  0,                         /* xBegin */
+  0,                         /* xSync */
+  0,                         /* xCommit */
+  0,                         /* xRollback */
+  0,                         /* xFindMethod */
+  0,                         /* xRename */
+  0,                         /* xSavepoint */
+  0,                         /* xRelease */
+  0                          /* xRollbackTo */
+};
 
-static int removeNode(Rtree *pRtree, RtreeNode *pNode, int iHeight){
-  int rc;
-  int rc2;
-  RtreeNode *pParent = 0;
-  int iCell;
+/* The methods of the json_tree virtual table. */
+static sqlite3_module jsonTreeModule = {
+  0,                         /* iVersion */
+  0,                         /* xCreate */
+  jsonEachConnect,           /* xConnect */
+  jsonEachBestIndex,         /* xBestIndex */
+  jsonEachDisconnect,        /* xDisconnect */
+  0,                         /* xDestroy */
+  jsonEachOpenTree,          /* xOpen - open a cursor */
+  jsonEachClose,             /* xClose - close a cursor */
+  jsonEachFilter,            /* xFilter - configure scan constraints */
+  jsonEachNext,              /* xNext - advance a cursor */
+  jsonEachEof,               /* xEof - check for end of scan */
+  jsonEachColumn,            /* xColumn - read data */
+  jsonEachRowid,             /* xRowid - read data */
+  0,                         /* xUpdate */
+  0,                         /* xBegin */
+  0,                         /* xSync */
+  0,                         /* xCommit */
+  0,                         /* xRollback */
+  0,                         /* xFindMethod */
+  0,                         /* xRename */
+  0,                         /* xSavepoint */
+  0,                         /* xRelease */
+  0                          /* xRollbackTo */
+};
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
 
-  assert( pNode->nRef==1 );
+/****************************************************************************
+** The following routines are the only publically visible identifiers in this
+** file.  Call the following routines in order to register the various SQL
+** functions and the virtual table implemented by this file.
+****************************************************************************/
 
-  /* 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;
-  }
+SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){
+  int rc = SQLITE_OK;
+  unsigned int i;
+  static const struct {
+     const char *zName;
+     int nArg;
+     int flag;
+     void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
+  } aFunc[] = {
+    { "json",                 1, 0,   jsonRemoveFunc        },
+    { "json_array",          -1, 0,   jsonArrayFunc         },
+    { "json_array_length",    1, 0,   jsonArrayLengthFunc   },
+    { "json_array_length",    2, 0,   jsonArrayLengthFunc   },
+    { "json_extract",        -1, 0,   jsonExtractFunc       },
+    { "json_insert",         -1, 0,   jsonSetFunc           },
+    { "json_object",         -1, 0,   jsonObjectFunc        },
+    { "json_patch",           2, 0,   jsonPatchFunc         },
+    { "json_quote",           1, 0,   jsonQuoteFunc         },
+    { "json_remove",         -1, 0,   jsonRemoveFunc        },
+    { "json_replace",        -1, 0,   jsonReplaceFunc       },
+    { "json_set",            -1, 1,   jsonSetFunc           },
+    { "json_type",            1, 0,   jsonTypeFunc          },
+    { "json_type",            2, 0,   jsonTypeFunc          },
+    { "json_valid",           1, 0,   jsonValidFunc         },
 
-  /* 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;
+#if SQLITE_DEBUG
+    /* DEBUG and TESTING functions */
+    { "json_parse",           1, 0,   jsonParseFunc         },
+    { "json_test1",           1, 0,   jsonTest1Func         },
+#endif
+  };
+  static const struct {
+     const char *zName;
+     int nArg;
+     void (*xStep)(sqlite3_context*,int,sqlite3_value**);
+     void (*xFinal)(sqlite3_context*);
+     void (*xValue)(sqlite3_context*);
+  } aAgg[] = {
+    { "json_group_array",     1,
+      jsonArrayStep,   jsonArrayFinal,  jsonArrayValue  },
+    { "json_group_object",    2,
+      jsonObjectStep,  jsonObjectFinal, jsonObjectValue },
+  };
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+  static const struct {
+     const char *zName;
+     sqlite3_module *pModule;
+  } aMod[] = {
+    { "json_each",            &jsonEachModule               },
+    { "json_tree",            &jsonTreeModule               },
+  };
+#endif
+  for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
+    rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg,
+                                 SQLITE_UTF8 | SQLITE_DETERMINISTIC, 
+                                 (void*)&aFunc[i].flag,
+                                 aFunc[i].xFunc, 0, 0);
   }
-
-  /* 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;
+#ifndef SQLITE_OMIT_WINDOWFUNC
+  for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
+    rc = sqlite3_create_window_function(db, aAgg[i].zName, aAgg[i].nArg,
+                                 SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
+                                 aAgg[i].xStep, aAgg[i].xFinal,
+                                 aAgg[i].xValue, jsonGroupInverse, 0);
   }
-  
-  /* 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; ii<nCell; ii++){
-      RtreeCell cell;
-      nodeGetCell(pRtree, pNode, ii, &cell);
-      cellUnion(pRtree, &box, &cell);
-    }
-    box.iRowid = pNode->iNode;
-    rc = nodeParentIndex(pRtree, pNode, &ii);
-    if( rc==SQLITE_OK ){
-      nodeOverwriteCell(pRtree, pParent, &box, ii);
-      rc = fixBoundingBox(pRtree, pParent);
-    }
+#endif
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+  for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){
+    rc = sqlite3_create_module(db, aMod[i].zName, aMod[i].pModule, 0);
   }
+#endif
   return rc;
 }
 
-/*
-** 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)<RTREE_MINCELLS(pRtree) ){
-      rc = removeNode(pRtree, pNode, iHeight);
-    }else{
-      rc = fixBoundingBox(pRtree, pNode);
-    }
-  }
-
-  return rc;
-}
 
-static int Reinsert(
-  Rtree *pRtree, 
-  RtreeNode *pNode, 
-  RtreeCell *pCell, 
-  int iHeight
+#ifndef SQLITE_CORE
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+SQLITE_API int sqlite3_json_init(
+  sqlite3 *db, 
+  char **pzErrMsg, 
+  const sqlite3_api_routines *pApi
 ){
-  int *aOrder;
-  int *aSpare;
-  RtreeCell *aCell;
-  RtreeDValue *aDistance;
-  int nCell;
-  RtreeDValue aCenterCoord[RTREE_MAX_DIMENSIONS];
-  int iDim;
-  int ii;
-  int rc = SQLITE_OK;
-  int n;
-
-  memset(aCenterCoord, 0, sizeof(RtreeDValue)*RTREE_MAX_DIMENSIONS);
-
-  nCell = NCELL(pNode)+1;
-  n = (nCell+1)&(~1);
+  SQLITE_EXTENSION_INIT2(pApi);
+  (void)pzErrMsg;  /* Unused parameter */
+  return sqlite3Json1Init(db);
+}
+#endif
+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1) */
 
-  /* Allocate the buffers used by this operation. The allocation is
-  ** relinquished before this function returns.
-  */
-  aCell = (RtreeCell *)sqlite3_malloc(n * (
-    sizeof(RtreeCell)     +         /* aCell array */
-    sizeof(int)           +         /* aOrder array */
-    sizeof(int)           +         /* aSpare array */
-    sizeof(RtreeDValue)             /* aDistance array */
-  ));
-  if( !aCell ){
-    return SQLITE_NOMEM;
-  }
-  aOrder    = (int *)&aCell[n];
-  aSpare    = (int *)&aOrder[n];
-  aDistance = (RtreeDValue *)&aSpare[n];
+/************** End of json1.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.
+*/
 
-  for(ii=0; ii<nCell; ii++){
-    if( ii==(nCell-1) ){
-      memcpy(&aCell[ii], pCell, sizeof(RtreeCell));
-    }else{
-      nodeGetCell(pRtree, pNode, ii, &aCell[ii]);
-    }
-    aOrder[ii] = ii;
-    for(iDim=0; iDim<pRtree->nDim; iDim++){
-      aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2]);
-      aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2+1]);
-    }
-  }
-  for(iDim=0; iDim<pRtree->nDim; iDim++){
-    aCenterCoord[iDim] = (aCenterCoord[iDim]/(nCell*(RtreeDValue)2));
-  }
+/*
+** 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.  If the r-tree contains auxiliary columns, those are stored
+** on the end of the %_rowid table.
+**
+** 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.
+*/
 
-  for(ii=0; ii<nCell; ii++){
-    aDistance[ii] = RTREE_ZERO;
-    for(iDim=0; iDim<pRtree->nDim; iDim++){
-      RtreeDValue coord = (DCOORD(aCell[ii].aCoord[iDim*2+1]) - 
-                               DCOORD(aCell[ii].aCoord[iDim*2]));
-      aDistance[ii] += (coord-aCenterCoord[iDim])*(coord-aCenterCoord[iDim]);
-    }
-  }
+#if !defined(SQLITE_CORE) \
+  || (defined(SQLITE_ENABLE_RTREE) && !defined(SQLITE_OMIT_VIRTUALTABLE))
 
-  SortByDistance(aOrder, nCell, aDistance, aSpare);
-  nodeZero(pRtree, pNode);
+#ifndef SQLITE_CORE
+/*   #include "sqlite3ext.h" */
+  SQLITE_EXTENSION_INIT1
+#else
+/*   #include "sqlite3.h" */
+#endif
 
-  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 && ii<nCell; ii++){
-    /* Find a node to store this cell in. pNode->iNode 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;
-      }
-    }
-  }
+/* #include <string.h> */
+/* #include <assert.h> */
+/* #include <stdio.h> */
 
-  sqlite3_free(aCell);
-  return rc;
-}
+#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
 
-/*
-** Insert cell pCell into node pNode. Node pNode is the head of a 
-** subtree iHeight high (leaf nodes have iHeight==0).
+/*  The following macro is used to suppress compiler warnings.
 */
-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;
-}
+#ifndef UNUSED_PARAMETER
+# define UNUSED_PARAMETER(x) (void)(x)
+#endif
 
-static int reinsertNodeContent(Rtree *pRtree, RtreeNode *pNode){
-  int ii;
-  int rc = SQLITE_OK;
-  int nCell = NCELL(pNode);
+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;
 
-  for(ii=0; rc==SQLITE_OK && ii<nCell; ii++){
-    RtreeNode *pInsert;
-    RtreeCell cell;
-    nodeGetCell(pRtree, pNode, ii, &cell);
+/* The rtree may have between 1 and RTREE_MAX_DIMENSIONS dimensions. */
+#define RTREE_MAX_DIMENSIONS 5
 
-    /* Find a node to store this cell in. pNode->iNode 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;
-}
+/* Maximum number of auxiliary columns */
+#define RTREE_MAX_AUX_COLUMN 100
 
-/*
-** Select a currently unused rowid for a new r-tree record.
+/* 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.
 */
-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;
-}
+#define HASHSIZE 97
 
-/*
-** Remove the entry with rowid=iDelete from the r-tree structure.
+/* 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.
 */
-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 = 0;           /* Root node of rtree structure */
-
+#define RTREE_DEFAULT_ROWEST 1048576
+#define RTREE_MIN_ROWEST         100
 
-  /* Obtain a reference to the root node to initialize Rtree.iDepth */
-  rc = nodeAcquire(pRtree, 1, 0, &pRoot);
+/* 
+** 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 */
+  u8 nAux;                    /* # of auxiliary columns in %_rowid */
+  u8 nAuxNotNull;             /* Number of initial not-null aux columns */
+  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 */
+  u32 nNodeRef;               /* Number RtreeNodes with positive nRef */
+  char *zReadAuxSql;          /* SQL for statement to read aux data */
 
-  /* Obtain a reference to the leaf node that contains the entry 
-  ** about to be deleted. 
+  /* 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).
   */
-  if( rc==SQLITE_OK ){
-    rc = findLeafNode(pRtree, iDelete, &pLeaf, 0);
-  }
+  RtreeNode *pDeleted;
+  int iReinsertHeight;        /* Height of sub-trees Reinsert() has run on */
 
-  /* 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;
-    }
-  }
+  /* Blob I/O on xxx_node */
+  sqlite3_blob *pNodeBlob;
 
-  /* Delete the corresponding entry in the <rtree>_rowid table. */
-  if( rc==SQLITE_OK ){
-    sqlite3_bind_int64(pRtree->pDeleteRowid, 1, iDelete);
-    sqlite3_step(pRtree->pDeleteRowid);
-    rc = sqlite3_reset(pRtree->pDeleteRowid);
-  }
+  /* Statements to read/write/delete a record from xxx_node */
+  sqlite3_stmt *pWriteNode;
+  sqlite3_stmt *pDeleteNode;
 
-  /* 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 = 0;
-    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;
-    }
-  }
+  /* Statements to read/write/delete a record from xxx_rowid */
+  sqlite3_stmt *pReadRowid;
+  sqlite3_stmt *pWriteRowid;
+  sqlite3_stmt *pDeleteRowid;
 
-  /* 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;
-    pRtree->nNodeRef--;
-    sqlite3_free(pLeaf);
-  }
+  /* Statements to read/write/delete a record from xxx_parent */
+  sqlite3_stmt *pReadParent;
+  sqlite3_stmt *pWriteParent;
+  sqlite3_stmt *pDeleteParent;
 
-  /* Release the reference to the root node. */
-  if( rc==SQLITE_OK ){
-    rc = nodeRelease(pRtree, pRoot);
-  }else{
-    nodeRelease(pRtree, pRoot);
-  }
+  /* Statement for writing to the "aux:" fields, if there are any */
+  sqlite3_stmt *pWriteAux;
 
-  return rc;
-}
+  RtreeNode *aHash[HASHSIZE]; /* Hash table of in-memory nodes. */ 
+};
+
+/* Possible values for Rtree.eCoordType: */
+#define RTREE_COORD_REAL32 0
+#define RTREE_COORD_INT32  1
 
 /*
-** Rounding constants for float->double conversion.
+** If SQLITE_RTREE_INT_ONLY is defined, then this virtual table will
+** only deal with integer coordinates.  No floating point operations
+** will be done.
 */
-#define RNDTOWARDS  (1.0 - 1.0/8388608.0)  /* Round towards zero */
-#define RNDAWAY     (1.0 + 1.0/8388608.0)  /* Round away from zero */
+#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
 
-#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.
+** 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.
 */
-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( f<d ){
-    f = (float)(d*(d<0 ? RNDTOWARDS : RNDAWAY));
-  }
-  return f;
-}
-#endif /* !defined(SQLITE_RTREE_INT_ONLY) */
+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 */
+};
 
 /*
-** A constraint has failed while inserting a row into an rtree table. 
-** Assuming no OOM error occurs, this function sets the error message 
-** (at pRtree->base.zErrMsg) to an appropriate value and returns
-** SQLITE_CONSTRAINT.
+** The minimum number of cells allowed for a node is a third of the 
+** maximum. In Gutman's notation:
 **
-** 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.
+**     m = M/3
 **
-** If an OOM occurs, SQLITE_NOMEM is returned instead of SQLITE_CONSTRAINT.
+** If an R*-tree "Reinsert" operation is required, the same number of
+** cells are removed from the overfull node and reinserted into the tree.
 */
-static int rtreeConstraintError(Rtree *pRtree, int iCol){
-  sqlite3_stmt *pStmt = 0;
-  char *zSql; 
-  int rc;
+#define RTREE_MINCELLS(p) ((((p)->iNodeSize-4)/(p)->nBytesPerCell)/3)
+#define RTREE_REINSERT(p) RTREE_MINCELLS(p)
+#define RTREE_MAXCELLS 51
 
-  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);
+/*
+** 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 
+** 3^40 is greater than 2^64, an r-tree structure always has a depth of
+** 40 or less.
+*/
+#define RTREE_MAX_DEPTH 40
 
-  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);
-}
+/*
+** 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 */
+  u8 bAuxValid;                     /* True if pReadAux 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 */
+  sqlite3_stmt *pReadAux;           /* Statement to read aux-data */
+  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))
 
 /*
-** The xUpdate method for rtree module virtual tables.
+** 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.
 */
-static int rtreeUpdate(
-  sqlite3_vtab *pVtab, 
-  int nData, 
-  sqlite3_value **aData, 
-  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 */
+union RtreeCoord {
+  RtreeValue f;      /* Floating point value */
+  int i;             /* Integer value */
+  u32 u;             /* Unsigned for byte-order conversions */
+};
 
-  if( pRtree->nNodeRef ){
-    /* Unable to write to the btree while another cursor is reading from it,
-    ** since the write might do a rebalance which would disrupt the read
-    ** cursor. */
-    return SQLITE_LOCKED_VTAB;
-  }
-  rtreeReference(pRtree);
-  assert(nData>=1);
+/*
+** 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
 
-  cell.iRowid = 0;  /* Used only to suppress a compiler warning */
+/*
+** 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 */
+};
 
-  /* 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;
-    int nn = nData - 4;
+/* 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() */
 
-    if( nn > pRtree->nDim2 ) nn = pRtree->nDim2;
-    /* Populate the cell.aCoord[] array. The first coordinate is aData[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.
-    */
 
-#ifndef SQLITE_RTREE_INT_ONLY
-    if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
-      for(ii=0; ii<nn; ii+=2){
-        cell.aCoord[ii].f = rtreeValueDown(aData[ii+3]);
-        cell.aCoord[ii+1].f = rtreeValueUp(aData[ii+4]);
-        if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){
-          rc = rtreeConstraintError(pRtree, ii+1);
-          goto constraint;
-        }
-      }
-    }else
+/* 
+** 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;
+};
+
+/*
+** 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 iSize;                  /* Size of this object */
+  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
-    {
-      for(ii=0; ii<nn; ii+=2){
-        cell.aCoord[ii].i = sqlite3_value_int(aData[ii+3]);
-        cell.aCoord[ii+1].i = sqlite3_value_int(aData[ii+4]);
-        if( cell.aCoord[ii].i>cell.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(aData[2])!=SQLITE_NULL ){
-      cell.iRowid = sqlite3_value_int64(aData[2]);
-      if( sqlite3_value_type(aData[0])==SQLITE_NULL
-       || sqlite3_value_int64(aData[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;
-    }
-  }
+/* 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
 
-  /* If aData[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(aData[0])!=SQLITE_NULL ){
-    rc = rtreeDeleteRowid(pRtree, sqlite3_value_int64(aData[0]));
-  }
+/* 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
 
-  /* If the aData[] array contains more than one element, elements
-  ** (aData[2]..aData[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;
+/*
+** 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
 
-    /* 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;
-      }
-    }
-    if( pRtree->nAux ){
-      sqlite3_stmt *pUp = pRtree->pWriteAux;
-      int jj;
-      sqlite3_bind_int64(pUp, 1, *pRowid);
-      for(jj=0; jj<pRtree->nAux; jj++){
-        sqlite3_bind_value(pUp, jj+2, aData[pRtree->nDim2+3+jj]);
-      }
-      sqlite3_step(pUp);
-      rc = sqlite3_reset(pUp);
-    }
-  }
+/* 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
 
-constraint:
-  rtreeRelease(pRtree);
-  return rc;
+/*
+** 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
 }
 
 /*
-** Called when a transaction starts.
+** 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 int rtreeBeginTransaction(sqlite3_vtab *pVtab){
-  Rtree *pRtree = (Rtree *)pVtab;
-  assert( pRtree->inWrTrans==0 );
-  pRtree->inWrTrans++;
-  return SQLITE_OK;
+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;
 }
 
 /*
-** Called when a transaction completes (either by COMMIT or ROLLBACK).
-** The sqlite3_blob object should be released at this point.
+** Increment the reference count of node p.
 */
-static int rtreeEndTransaction(sqlite3_vtab *pVtab){
-  Rtree *pRtree = (Rtree *)pVtab;
-  pRtree->inWrTrans = 0;
-  nodeBlobReset(pRtree);
-  return SQLITE_OK;
+static void nodeReference(RtreeNode *p){
+  if( p ){
+    assert( p->nRef>0 );
+    p->nRef++;
+  }
 }
 
 /*
-** The xRename method for rtree module virtual tables.
+** Clear the content of node p (set all bytes to 0x00).
 */
-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;
+static void nodeZero(Rtree *pRtree, RtreeNode *p){
+  memset(&p->zData[2], 0, pRtree->iNodeSize-2);
+  p->isDirty = 1;
 }
 
 /*
-** 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 <tablename>;    -- Would fail with SQLITE_LOCKED
-**   COMMIT;
+** Given a node number iNode, return the corresponding key to use
+** in the Rtree.aHash table.
 */
-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;
+static int nodeHash(i64 iNode){
+  return iNode % HASHSIZE;
 }
 
 /*
-** 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.
+** Search the node hash table for node iNode. If found, return a pointer
+** to it. Otherwise, return 0.
 */
-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;
+static RtreeNode *nodeHashLookup(Rtree *pRtree, i64 iNode){
+  RtreeNode *p;
+  for(p=pRtree->aHash[nodeHash(iNode)]; p && p->iNode!=iNode; p=p->pNext);
+  return p;
+}
 
-  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;
-    }
+/*
+** 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;
+}
 
-    if( rc==SQLITE_OK ){
-      if( nRow==0 ){
-        pRtree->nRowEst = RTREE_DEFAULT_ROWEST;
-      }else{
-        pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST);
-      }
-    }
-    sqlite3_free(zSql);
+/*
+** 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;
   }
+}
 
-  return rc;
+/*
+** 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;
+    pRtree->nNodeRef++;
+    pNode->pParent = pParent;
+    pNode->isDirty = 1;
+    nodeReference(pParent);
+  }
+  return pNode;
 }
 
-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 */
-};
+/*
+** 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);
+  }
+}
 
-static int rtreeSqlInit(
-  Rtree *pRtree, 
-  sqlite3 *db, 
-  const char *zDb, 
-  const char *zPrefix, 
-  int isCreate
+/*
+** 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;
 
-  #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_str *p = sqlite3_str_new(db);
-    int ii;
-    sqlite3_str_appendf(p,
-       "CREATE TABLE \"%w\".\"%w_rowid\"(rowid INTEGER PRIMARY KEY,nodeno",
-       zDb, zPrefix);
-    for(ii=0; ii<pRtree->nAux; ii++){
-      sqlite3_str_appendf(p,",a%d",ii);
-    }
-    sqlite3_str_appendf(p,
-      ");CREATE TABLE \"%w\".\"%w_node\"(nodeno INTEGER PRIMARY KEY,data);",
-      zDb, zPrefix);
-    sqlite3_str_appendf(p,
-    "CREATE TABLE \"%w\".\"%w_parent\"(nodeno INTEGER PRIMARY KEY,parentnode);",
-      zDb, zPrefix);
-    sqlite3_str_appendf(p,
-       "INSERT INTO \"%w\".\"%w_node\"VALUES(1,zeroblob(%d))",
-       zDb, zPrefix, pRtree->iNodeSize);
-    zCreate = sqlite3_str_finish(p);
-    if( !zCreate ){
-      return SQLITE_NOMEM;
-    }
-    rc = sqlite3_exec(db, zCreate, 0, 0, 0);
-    sqlite3_free(zCreate);
-    if( rc!=SQLITE_OK ){
-      return rc;
+  /* 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))!=0 ){
+    assert( !pParent || !pNode->pParent || pNode->pParent==pParent );
+    if( pParent && !pNode->pParent ){
+      pParent->nRef++;
+      pNode->pParent = pParent;
     }
+    pNode->nRef++;
+    *ppNode = pNode;
+    return SQLITE_OK;
   }
 
-  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; i<N_STATEMENT && rc==SQLITE_OK; i++){
-    char *zSql;
-    const char *zFormat;
-    if( i!=3 || pRtree->nAux==0 ){
-       zFormat = azSql[i];
-    }else {
-       /* An UPSERT is very slightly slower than REPLACE, but it is needed
-       ** if there are auxiliary columns */
-       zFormat = "INSERT INTO\"%w\".\"%w_rowid\"(rowid,nodeno)VALUES(?1,?2)"
-                  "ON CONFLICT(rowid)DO UPDATE SET nodeno=excluded.nodeno";
-    }
-    zSql = sqlite3_mprintf(zFormat, zDb, zPrefix);
-    if( zSql ){
-      rc = sqlite3_prepare_v3(db, zSql, -1, SQLITE_PREPARE_PERSISTENT,
-                              appStmt[i], 0); 
-    }else{
-      rc = SQLITE_NOMEM;
+  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;
     }
-    sqlite3_free(zSql);
   }
-  if( pRtree->nAux ){
-    pRtree->zReadAuxSql = sqlite3_mprintf(
-       "SELECT * FROM \"%w\".\"%w_rowid\" WHERE rowid=?1",
-       zDb, zPrefix);
-    if( pRtree->zReadAuxSql==0 ){
+  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{
-      sqlite3_str *p = sqlite3_str_new(db);
-      int ii;
-      char *zSql;
-      sqlite3_str_appendf(p, "UPDATE \"%w\".\"%w_rowid\"SET ", zDb, zPrefix);
-      for(ii=0; ii<pRtree->nAux; ii++){
-        if( ii ) sqlite3_str_append(p, ",", 1);
-        sqlite3_str_appendf(p,"a%d=?%d",ii,ii+2);
-      }
-      sqlite3_str_appendf(p, " WHERE rowid=?1");
-      zSql = sqlite3_str_finish(p);
-      if( zSql==0 ){
-        rc = SQLITE_NOMEM;
-      }else{
-        rc = sqlite3_prepare_v3(db, zSql, -1, SQLITE_PREPARE_PERSISTENT,
-                                &pRtree->pWriteAux, 0); 
-        sqlite3_free(zSql);
-      }
+      pNode->pParent = pParent;
+      pNode->zData = (u8 *)&pNode[1];
+      pNode->nRef = 1;
+      pRtree->nNodeRef++;
+      pNode->iNode = iNode;
+      pNode->isDirty = 0;
+      pNode->pNext = 0;
+      rc = sqlite3_blob_read(pRtree->pNodeBlob, pNode->zData,
+                             pRtree->iNodeSize, 0);
+      nodeReference(pParent);
     }
   }
 
-  return rc;
-}
+  /* 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;
+    }
+  }
 
-/*
-** The second argument to this function contains the text of an SQL statement
-** that returns a single integer value. The statement is compiled and executed
-** using database connection db. If successful, the integer value returned
-** is written to *piVal and SQLITE_OK returned. Otherwise, an SQLite error
-** code is returned and the value of *piVal after returning is not defined.
-*/
-static int getIntFromStmt(sqlite3 *db, const char *zSql, int *piVal){
-  int rc = SQLITE_NOMEM;
-  if( zSql ){
-    sqlite3_stmt *pStmt = 0;
-    rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
-    if( rc==SQLITE_OK ){
-      if( SQLITE_ROW==sqlite3_step(pStmt) ){
-        *piVal = sqlite3_column_int(pStmt, 0);
-      }
-      rc = sqlite3_finalize(pStmt);
+  /* 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;
     }
   }
-  return rc;
-}
 
-/*
-** This function is called from within the xConnect() or xCreate() method to
-** determine the node-size used by the rtree table being created or connected
-** to. If successful, pRtree->iNodeSize 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)<pRtree->iNodeSize ){
-        pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS;
-      }
+  if( rc==SQLITE_OK ){
+    if( pNode!=0 ){
+      nodeHashInsert(pRtree, pNode);
     }else{
-      *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+      rc = SQLITE_CORRUPT_VTAB;
     }
+    *ppNode = pNode;
   }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));
-    }else if( pRtree->iNodeSize<(512-64) ){
-      rc = SQLITE_CORRUPT_VTAB;
-      *pzErr = sqlite3_mprintf("undersize RTree blobs in \"%q_node\"",
-                               pRtree->zName);
+    if( pNode ){
+      pRtree->nNodeRef--;
+      sqlite3_free(pNode);
     }
+    *ppNode = 0;
   }
 
-  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...
+/*
+** Overwrite cell iCell of node pNode with the contents of pCell.
 */
-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 */
+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 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);
-  sqlite3_str *pSql;
-  char *zSql;
-  int ii = 4;
-  int iErr;
+  int ii;
+  u8 *p = &pNode->zData[4 + pRtree->nBytesPerCell*iCell];
+  p += writeInt64(p, pCell->iRowid);
+  for(ii=0; ii<pRtree->nDim2; ii++){
+    p += writeCoord(p, &pCell->aCoord[ii]);
+  }
+  pNode->isDirty = 1;
+}
 
-  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 */
-    "Auxiliary rtree columns must be last"                /* 4 */
-  };
+/*
+** 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;
+}
 
-  assert( RTREE_MAX_AUX_COLUMN<256 ); /* Aux columns counted by a u8 */
-  if( argc>RTREE_MAX_AUX_COLUMN+3 ){
-    *pzErr = sqlite3_mprintf("%s", aErrMsg[3]);
-    return SQLITE_ERROR;
-  }
+/*
+** 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 */
 
-  sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
+  nMaxCell = (pRtree->iNodeSize-4)/pRtree->nBytesPerCell;
+  nCell = NCELL(pNode);
 
-  /* 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;
+  assert( nCell<=nMaxCell );
+  if( nCell<nMaxCell ){
+    nodeOverwriteCell(pRtree, pNode, pCell, nCell);
+    writeInt16(&pNode->zData[2], nCell+1);
+    pNode->isDirty = 1;
   }
-  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->eCoordType = (u8)eCoordType;
-  memcpy(pRtree->zDb, argv[1], nDb);
-  memcpy(pRtree->zName, argv[2], nName);
 
+  return (nCell==nMaxCell);
+}
 
-  /* Create/Connect to the underlying relational database schema. If
-  ** that is successful, call sqlite3_declare_vtab() to configure
-  ** the r-tree table schema.
-  */
-  pSql = sqlite3_str_new(db);
-  sqlite3_str_appendf(pSql, "CREATE TABLE x(%s", argv[3]);
-  for(ii=4; ii<argc; ii++){
-    if( argv[ii][0]=='+' ){
-      pRtree->nAux++;
-      sqlite3_str_appendf(pSql, ",%s", argv[ii]+1);
-    }else if( pRtree->nAux>0 ){
-      break;
+/*
+** 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{
-      pRtree->nDim2++;
-      sqlite3_str_appendf(pSql, ",%s", argv[ii]);
+      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);
+    sqlite3_bind_null(p, 2);
+    if( pNode->iNode==0 && rc==SQLITE_OK ){
+      pNode->iNode = sqlite3_last_insert_rowid(pRtree->db);
+      nodeHashInsert(pRtree, pNode);
     }
   }
-  sqlite3_str_appendf(pSql, ");");
-  zSql = sqlite3_str_finish(pSql);
-  if( !zSql ){
-    rc = SQLITE_NOMEM;
-  }else if( ii<argc ){
-    *pzErr = sqlite3_mprintf("%s", aErrMsg[4]);
-    rc = SQLITE_ERROR;
-  }else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){
-    *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
-  }
-  sqlite3_free(zSql);
-  if( rc ) goto rtreeInit_fail;
-  pRtree->nDim = pRtree->nDim2/2;
-  if( pRtree->nDim<1 ){
-    iErr = 2;
-  }else if( pRtree->nDim2>RTREE_MAX_DIMENSIONS*2 ){
-    iErr = 3;
-  }else if( pRtree->nDim2 % 2 ){
-    iErr = 1;
-  }else{
-    iErr = 0;
-  }
-  if( iErr ){
-    *pzErr = sqlite3_mprintf("%s", aErrMsg[iErr]);
-    goto rtreeInit_fail;
-  }
-  pRtree->nBytesPerCell = 8 + pRtree->nDim2*4;
+  return rc;
+}
 
-  /* Figure out the node size to use. */
-  rc = getNodeSize(db, pRtree, isCreate, pzErr);
-  if( rc ) goto rtreeInit_fail;
-  rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate);
-  if( rc ){
-    *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
-    goto rtreeInit_fail;
+/*
+** 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 );
+    assert( pRtree->nNodeRef>0 );
+    pNode->nRef--;
+    if( pNode->nRef==0 ){
+      pRtree->nNodeRef--;
+      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);
+    }
   }
-
-  *ppVtab = (sqlite3_vtab *)pRtree;
-  return SQLITE_OK;
-
-rtreeInit_fail:
-  if( rc==SQLITE_OK ) rc = SQLITE_ERROR;
-  assert( *ppVtab==0 );
-  assert( pRtree->nBusy==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 
-** <num-dimension>*2 coordinates.
+** 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 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; ii<NCELL(&node); ii++){
-    char zCell[512];
-    int nCell = 0;
-    RtreeCell cell;
-    int jj;
-
-    nodeGetCell(&tree, &node, ii, &cell);
-    sqlite3_snprintf(512-nCell,&zCell[nCell],"%lld", cell.iRowid);
-    nCell = (int)strlen(zCell);
-    for(jj=0; jj<tree.nDim2; jj++){
-#ifndef SQLITE_RTREE_INT_ONLY
-      sqlite3_snprintf(512-nCell,&zCell[nCell], " %g",
-                       (double)cell.aCoord[jj].f);
-#else
-      sqlite3_snprintf(512-nCell,&zCell[nCell], " %d",
-                       cell.aCoord[jj].i);
-#endif
-      nCell = (int)strlen(zCell);
-    }
-
-    if( zText ){
-      char *zTextNew = sqlite3_mprintf("%s {%s}", zText, zCell);
-      sqlite3_free(zText);
-      zText = zTextNew;
-    }else{
-      zText = sqlite3_mprintf("{%s}", zCell);
-    }
-  }
-  
-  sqlite3_result_text(ctx, zText, -1, sqlite3_free);
+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( iCell<NCELL(pNode) );
+  return readInt64(&pNode->zData[4 + pRtree->nBytesPerCell*iCell]);
 }
 
-/* This routine implements an SQL function that returns the "depth" parameter
-** from the front of a blob that is an r-tree node.  For example:
-**
-**     SELECT rtreedepth(data) FROM rt_node WHERE nodeno=1;
-**
-** The depth value is 0 for all nodes other than the root node, and the root
-** node always has nodeno=1, so the example above is the primary use for this
-** routine.  This routine is intended for testing and analysis only.
+/*
+** Return coordinate iCoord from cell iCell in node pNode.
 */
-static void rtreedepth(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
-  UNUSED_PARAMETER(nArg);
-  if( sqlite3_value_type(apArg[0])!=SQLITE_BLOB 
-   || sqlite3_value_bytes(apArg[0])<2
-  ){
-    sqlite3_result_error(ctx, "Invalid argument to rtreedepth()", -1); 
-  }else{
-    u8 *zBlob = (u8 *)sqlite3_value_blob(apArg[0]);
-    sqlite3_result_int(ctx, readInt16(zBlob));
-  }
+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);
 }
 
 /*
-** Context object passed between the various routines that make up the
-** implementation of integrity-check function rtreecheck().
+** Deserialize cell iCell of node pNode. Populate the structure pointed
+** to by pCell with the results.
 */
-typedef struct RtreeCheck RtreeCheck;
-struct RtreeCheck {
-  sqlite3 *db;                    /* Database handle */
-  const char *zDb;                /* Database containing rtree table */
-  const char *zTab;               /* Name of rtree table */
-  int bInt;                       /* True for rtree_i32 table */
-  int nDim;                       /* Number of dimensions for this rtree tbl */
-  sqlite3_stmt *pGetNode;         /* Statement used to retrieve nodes */
-  sqlite3_stmt *aCheckMapping[2]; /* Statements to query %_parent/%_rowid */
-  int nLeaf;                      /* Number of leaf cells in table */
-  int nNonLeaf;                   /* Number of non-leaf cells in table */
-  int rc;                         /* Return code */
-  char *zReport;                  /* Message to report */
-  int nErr;                       /* Number of lines in zReport */
-};
+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( ii<pRtree->nDim2 );
+}
 
-#define RTREE_CHECK_MAX_ERROR 100
 
-/*
-** Reset SQL statement pStmt. If the sqlite3_reset() call returns an error,
-** and RtreeCheck.rc==SQLITE_OK, set RtreeCheck.rc to the error code.
+/* Forward declaration for the function that does the work of
+** the virtual table module xCreate() and xConnect() methods.
 */
-static void rtreeCheckReset(RtreeCheck *pCheck, sqlite3_stmt *pStmt){
-  int rc = sqlite3_reset(pStmt);
-  if( pCheck->rc==SQLITE_OK ) pCheck->rc = rc;
-}
+static int rtreeInit(
+  sqlite3 *, void *, int, const char *const*, sqlite3_vtab **, char **, int
+);
 
-/*
-** The second and subsequent arguments to this function are a format string
-** and printf style arguments. This function formats the string and attempts
-** to compile it as an SQL statement.
-**
-** If successful, a pointer to the new SQL statement is returned. Otherwise,
-** NULL is returned and an error code left in RtreeCheck.rc.
+/* 
+** Rtree virtual table module xCreate method.
 */
-static sqlite3_stmt *rtreeCheckPrepare(
-  RtreeCheck *pCheck,             /* RtreeCheck object */
-  const char *zFmt, ...           /* Format string and trailing args */
+static int rtreeCreate(
+  sqlite3 *db,
+  void *pAux,
+  int argc, const char *const*argv,
+  sqlite3_vtab **ppVtab,
+  char **pzErr
 ){
-  va_list ap;
-  char *z;
-  sqlite3_stmt *pRet = 0;
-
-  va_start(ap, zFmt);
-  z = sqlite3_vmprintf(zFmt, ap);
-
-  if( pCheck->rc==SQLITE_OK ){
-    if( z==0 ){
-      pCheck->rc = SQLITE_NOMEM;
-    }else{
-      pCheck->rc = sqlite3_prepare_v2(pCheck->db, z, -1, &pRet, 0);
-    }
-  }
+  return rtreeInit(db, pAux, argc, argv, ppVtab, pzErr, 1);
+}
 
-  sqlite3_free(z);
-  va_end(ap);
-  return pRet;
+/* 
+** 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);
 }
 
 /*
-** The second and subsequent arguments to this function are a printf()
-** style format string and arguments. This function formats the string and
-** appends it to the report being accumuated in pCheck.
+** Increment the r-tree reference count.
 */
-static void rtreeCheckAppendMsg(RtreeCheck *pCheck, const char *zFmt, ...){
-  va_list ap;
-  va_start(ap, zFmt);
-  if( pCheck->rc==SQLITE_OK && pCheck->nErr<RTREE_CHECK_MAX_ERROR ){
-    char *z = sqlite3_vmprintf(zFmt, ap);
-    if( z==0 ){
-      pCheck->rc = SQLITE_NOMEM;
-    }else{
-      pCheck->zReport = sqlite3_mprintf("%z%s%z", 
-          pCheck->zReport, (pCheck->zReport ? "\n" : ""), z
-      );
-      if( pCheck->zReport==0 ){
-        pCheck->rc = SQLITE_NOMEM;
-      }
-    }
-    pCheck->nErr++;
-  }
-  va_end(ap);
+static void rtreeReference(Rtree *pRtree){
+  pRtree->nBusy++;
 }
 
 /*
-** This function is a no-op if there is already an error code stored
-** in the RtreeCheck object indicated by the first argument. NULL is
-** returned in this case.
-**
-** Otherwise, the contents of rtree table node iNode are loaded from
-** the database and copied into a buffer obtained from sqlite3_malloc().
-** If no error occurs, a pointer to the buffer is returned and (*pnNode)
-** is set to the size of the buffer in bytes.
-**
-** Or, if an error does occur, NULL is returned and an error code left
-** in the RtreeCheck object. The final value of *pnNode is undefined in
-** this case.
+** Decrement the r-tree reference count. When the reference count reaches
+** zero the structure is deleted.
 */
-static u8 *rtreeCheckGetNode(RtreeCheck *pCheck, i64 iNode, int *pnNode){
-  u8 *pRet = 0;                   /* Return value */
-
-  assert( pCheck->rc==SQLITE_OK );
-  if( pCheck->pGetNode==0 ){
-    pCheck->pGetNode = rtreeCheckPrepare(pCheck,
-        "SELECT data FROM %Q.'%q_node' WHERE nodeno=?", 
-        pCheck->zDb, pCheck->zTab
-    );
-  }
-
-  if( pCheck->rc==SQLITE_OK ){
-    sqlite3_bind_int64(pCheck->pGetNode, 1, iNode);
-    if( sqlite3_step(pCheck->pGetNode)==SQLITE_ROW ){
-      int nNode = sqlite3_column_bytes(pCheck->pGetNode, 0);
-      const u8 *pNode = (const u8*)sqlite3_column_blob(pCheck->pGetNode, 0);
-      pRet = sqlite3_malloc(nNode);
-      if( pRet==0 ){
-        pCheck->rc = SQLITE_NOMEM;
-      }else{
-        memcpy(pRet, pNode, nNode);
-        *pnNode = nNode;
-      }
-    }
-    rtreeCheckReset(pCheck, pCheck->pGetNode);
-    if( pCheck->rc==SQLITE_OK && pRet==0 ){
-      rtreeCheckAppendMsg(pCheck, "Node %lld missing from database", iNode);
-    }
+static void rtreeRelease(Rtree *pRtree){
+  pRtree->nBusy--;
+  if( pRtree->nBusy==0 ){
+    pRtree->inWrTrans = 0;
+    assert( pRtree->nCursor==0 );
+    nodeBlobReset(pRtree);
+    assert( pRtree->nNodeRef==0 );
+    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_finalize(pRtree->pWriteAux);
+    sqlite3_free(pRtree->zReadAuxSql);
+    sqlite3_free(pRtree);
   }
+}
 
-  return pRet;
+/* 
+** Rtree virtual table module xDisconnect method.
+*/
+static int rtreeDisconnect(sqlite3_vtab *pVtab){
+  rtreeRelease((Rtree *)pVtab);
+  return SQLITE_OK;
 }
 
-/*
-** This function is used to check that the %_parent (if bLeaf==0) or %_rowid
-** (if bLeaf==1) table contains a specified entry. The schemas of the
-** two tables are:
-**
-**   CREATE TABLE %_parent(nodeno INTEGER PRIMARY KEY, parentnode INTEGER)
-**   CREATE TABLE %_rowid(rowid INTEGER PRIMARY KEY, nodeno INTEGER, ...)
-**
-** In both cases, this function checks that there exists an entry with
-** IPK value iKey and the second column set to iVal.
-**
+/* 
+** Rtree virtual table module xDestroy method.
 */
-static void rtreeCheckMapping(
-  RtreeCheck *pCheck,             /* RtreeCheck object */
-  int bLeaf,                      /* True for a leaf cell, false for interior */
-  i64 iKey,                       /* Key for mapping */
-  i64 iVal                        /* Expected value for mapping */
-){
+static int rtreeDestroy(sqlite3_vtab *pVtab){
+  Rtree *pRtree = (Rtree *)pVtab;
   int rc;
-  sqlite3_stmt *pStmt;
-  const char *azSql[2] = {
-    "SELECT parentnode FROM %Q.'%q_parent' WHERE nodeno=?1",
-    "SELECT nodeno FROM %Q.'%q_rowid' WHERE rowid=?1"
-  };
-
-  assert( bLeaf==0 || bLeaf==1 );
-  if( pCheck->aCheckMapping[bLeaf]==0 ){
-    pCheck->aCheckMapping[bLeaf] = rtreeCheckPrepare(pCheck,
-        azSql[bLeaf], pCheck->zDb, pCheck->zTab
-    );
+  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( pCheck->rc!=SQLITE_OK ) return;
-
-  pStmt = pCheck->aCheckMapping[bLeaf];
-  sqlite3_bind_int64(pStmt, 1, iKey);
-  rc = sqlite3_step(pStmt);
-  if( rc==SQLITE_DONE ){
-    rtreeCheckAppendMsg(pCheck, "Mapping (%lld -> %lld) missing from %s table",
-        iKey, iVal, (bLeaf ? "%_rowid" : "%_parent")
-    );
-  }else if( rc==SQLITE_ROW ){
-    i64 ii = sqlite3_column_int64(pStmt, 0);
-    if( ii!=iVal ){
-      rtreeCheckAppendMsg(pCheck, 
-          "Found (%lld -> %lld) in %s table, expected (%lld -> %lld)",
-          iKey, ii, (bLeaf ? "%_rowid" : "%_parent"), iKey, iVal
-      );
-    }
+  if( rc==SQLITE_OK ){
+    rtreeRelease(pRtree);
   }
-  rtreeCheckReset(pCheck, pStmt);
+
+  return rc;
 }
 
-/*
-** Argument pCell points to an array of coordinates stored on an rtree page.
-** This function checks that the coordinates are internally consistent (no
-** x1>x2 conditions) and adds an error message to the RtreeCheck object
-** if they are not.
-**
-** Additionally, if pParent is not NULL, then it is assumed to point to
-** the array of coordinates on the parent page that bound the page 
-** containing pCell. In this case it is also verified that the two
-** sets of coordinates are mutually consistent and an error message added
-** to the RtreeCheck object if they are not.
+/* 
+** Rtree virtual table module xOpen method.
 */
-static void rtreeCheckCellCoord(
-  RtreeCheck *pCheck, 
-  i64 iNode,                      /* Node id to use in error messages */
-  int iCell,                      /* Cell number to use in error messages */
-  u8 *pCell,                      /* Pointer to cell coordinates */
-  u8 *pParent                     /* Pointer to parent coordinates */
-){
-  RtreeCoord c1, c2;
-  RtreeCoord p1, p2;
-  int i;
+static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
+  int rc = SQLITE_NOMEM;
+  Rtree *pRtree = (Rtree *)pVTab;
+  RtreeCursor *pCsr;
 
-  for(i=0; i<pCheck->nDim; i++){
-    readCoord(&pCell[4*2*i], &c1);
-    readCoord(&pCell[4*(2*i + 1)], &c2);
+  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;
 
-    /* printf("%e, %e\n", c1.u.f, c2.u.f); */
-    if( pCheck->bInt ? c1.i>c2.i : c1.f>c2.f ){
-      rtreeCheckAppendMsg(pCheck, 
-          "Dimension %d of cell %d on node %lld is corrupt", i, iCell, iNode
-      );
-    }
+  return rc;
+}
 
-    if( pParent ){
-      readCoord(&pParent[4*2*i], &p1);
-      readCoord(&pParent[4*(2*i + 1)], &p2);
 
-      if( (pCheck->bInt ? c1.i<p1.i : c1.f<p1.f) 
-       || (pCheck->bInt ? c2.i>p2.i : c2.f>p2.f)
-      ){
-        rtreeCheckAppendMsg(pCheck, 
-            "Dimension %d of cell %d on node %lld is corrupt relative to parent"
-            , i, iCell, iNode
-        );
+/*
+** 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; i<pCsr->nConstraint; 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_finalize(pCsr->pReadAux);
+  sqlite3_free(pCsr->aPoint);
+  for(ii=0; ii<RTREE_CACHE_SZ; ii++) nodeRelease(pRtree, pCsr->aNode[ii]);
+  sqlite3_free(pCsr);
+  pRtree->nCursor--;
+  nodeBlobReset(pRtree);
+  return SQLITE_OK;
+}
+
 /*
-** Run rtreecheck() checks on node iNode, which is at depth iDepth within
-** the r-tree structure. Argument aParent points to the array of coordinates
-** that bound node iNode on the parent node.
+** Rtree virtual table module xEof method.
 **
-** If any problems are discovered, an error message is appended to the
-** report accumulated in the RtreeCheck object.
+** 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 void rtreeCheckNode(
-  RtreeCheck *pCheck,
-  int iDepth,                     /* Depth of iNode (0==leaf) */
-  u8 *aParent,                    /* Buffer containing parent coords */
-  i64 iNode                       /* Node to check */
-){
-  u8 *aNode = 0;
-  int nNode = 0;
-
-  assert( iNode==1 || aParent!=0 );
-  assert( pCheck->nDim>0 );
-
-  aNode = rtreeCheckGetNode(pCheck, iNode, &nNode);
-  if( aNode ){
-    if( nNode<4 ){
-      rtreeCheckAppendMsg(pCheck, 
-          "Node %lld is too small (%d bytes)", iNode, nNode
-      );
-    }else{
-      int nCell;                  /* Number of cells on page */
-      int i;                      /* Used to iterate through cells */
-      if( aParent==0 ){
-        iDepth = readInt16(aNode);
-        if( iDepth>RTREE_MAX_DEPTH ){
-          rtreeCheckAppendMsg(pCheck, "Rtree depth out of range (%d)", iDepth);
-          sqlite3_free(aNode);
-          return;
-        }
-      }
-      nCell = readInt16(&aNode[2]);
-      if( (4 + nCell*(8 + pCheck->nDim*2*4))>nNode ){
-        rtreeCheckAppendMsg(pCheck, 
-            "Node %lld is too small for cell count of %d (%d bytes)", 
-            iNode, nCell, nNode
-        );
-      }else{
-        for(i=0; i<nCell; i++){
-          u8 *pCell = &aNode[4 + i*(8 + pCheck->nDim*2*4)];
-          i64 iVal = readInt64(pCell);
-          rtreeCheckCellCoord(pCheck, iNode, i, &pCell[8], aParent);
-
-          if( iDepth>0 ){
-            rtreeCheckMapping(pCheck, 0, iVal, iNode);
-            rtreeCheckNode(pCheck, iDepth-1, &pCell[8], iVal);
-            pCheck->nNonLeaf++;
-          }else{
-            rtreeCheckMapping(pCheck, 1, iVal, iNode);
-            pCheck->nLeaf++;
-          }
-        }
-      }
-    }
-    sqlite3_free(aNode);
-  }
+static int rtreeEof(sqlite3_vtab_cursor *cur){
+  RtreeCursor *pCsr = (RtreeCursor *)cur;
+  return pCsr->atEOF;
 }
 
 /*
-** The second argument to this function must be either "_rowid" or
-** "_parent". This function checks that the number of entries in the
-** %_rowid or %_parent table is exactly nExpect. If not, it adds
-** an error message to the report in the RtreeCheck object indicated
-** by the first argument.
+** 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.
 */
-static void rtreeCheckCount(RtreeCheck *pCheck, const char *zTbl, i64 nExpect){
-  if( pCheck->rc==SQLITE_OK ){
-    sqlite3_stmt *pCount;
-    pCount = rtreeCheckPrepare(pCheck, "SELECT count(*) FROM %Q.'%q%s'",
-        pCheck->zDb, pCheck->zTab, zTbl
-    );
-    if( pCount ){
-      if( sqlite3_step(pCount)==SQLITE_ROW ){
-        i64 nActual = sqlite3_column_int64(pCount, 0);
-        if( nActual!=nExpect ){
-          rtreeCheckAppendMsg(pCheck, "Wrong number of entries in %%%s table"
-              " - expected %lld, actual %lld" , zTbl, nExpect, nActual
-          );
-        }
-      }
-      pCheck->rc = sqlite3_finalize(pCount);
-    }
-  }
+#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
 
 /*
-** This function does the bulk of the work for the rtree integrity-check.
-** It is called by rtreecheck(), which is the SQL function implementation.
+** Check the RTree node or entry given by pCellData and p against the MATCH
+** constraint pConstraint.  
 */
-static int rtreeCheckTable(
-  sqlite3 *db,                    /* Database handle to access db through */
-  const char *zDb,                /* Name of db ("main", "temp" etc.) */
-  const char *zTab,               /* Name of rtree table to check */
-  char **pzReport                 /* OUT: sqlite3_malloc'd report text */
+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 */
 ){
-  RtreeCheck check;               /* Common context for various routines */
-  sqlite3_stmt *pStmt = 0;        /* Used to find column count of rtree table */
-  int bEnd = 0;                   /* True if transaction should be closed */
-  int nAux = 0;                   /* Number of extra columns. */
+  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 */
 
-  /* Initialize the context object */
-  memset(&check, 0, sizeof(check));
-  check.db = db;
-  check.zDb = zDb;
-  check.zTab = zTab;
+  assert( pConstraint->op==RTREE_MATCH || pConstraint->op==RTREE_QUERY );
+  assert( nCoord==2 || nCoord==4 || nCoord==6 || nCoord==8 || nCoord==10 );
 
-  /* If there is not already an open transaction, open one now. This is
-  ** to ensure that the queries run as part of this integrity-check operate
-  ** on a consistent snapshot.  */
-  if( sqlite3_get_autocommit(db) ){
-    check.rc = sqlite3_exec(db, "BEGIN", 0, 0, 0);
-    bEnd = 1;
+  if( pConstraint->op==RTREE_QUERY && pSearch->iLevel==1 ){
+    pInfo->iRowid = readInt64(pCellData);
   }
-
-  /* Find the number of auxiliary columns */
-  if( check.rc==SQLITE_OK ){
-    pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab);
-    if( pStmt ){
-      nAux = sqlite3_column_count(pStmt) - 2;
-      sqlite3_finalize(pStmt);
+  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;
     }
-    check.rc = SQLITE_OK;
-  }
-
-  /* Find number of dimensions in the rtree table. */
-  pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.%Q", zDb, zTab);
-  if( pStmt ){
-    int rc;
-    check.nDim = (sqlite3_column_count(pStmt) - 1 - nAux) / 2;
-    if( check.nDim<1 ){
-      rtreeCheckAppendMsg(&check, "Schema corrupt or not an rtree");
-    }else if( SQLITE_ROW==sqlite3_step(pStmt) ){
-      check.bInt = (sqlite3_column_type(pStmt, 1)==SQLITE_INTEGER);
+  }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;
     }
-    rc = sqlite3_finalize(pStmt);
-    if( rc!=SQLITE_CORRUPT ) check.rc = rc;
   }
-
-  /* Do the actual integrity-check */
-  if( check.nDim>=1 ){
-    if( check.rc==SQLITE_OK ){
-      rtreeCheckNode(&check, 0, 0, 1);
+  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 || *prScore<RTREE_ZERO ){
+      *prScore = pInfo->rScore;
     }
-    rtreeCheckCount(&check, "_rowid", check.nLeaf);
-    rtreeCheckCount(&check, "_parent", check.nNonLeaf);
   }
+  return rc;
+}
 
-  /* Finalize SQL statements used by the integrity-check */
-  sqlite3_finalize(check.pGetNode);
-  sqlite3_finalize(check.aCheckMapping[0]);
-  sqlite3_finalize(check.aCheckMapping[1]);
+/* 
+** 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 */
 
-  /* If one was opened, close the transaction */
-  if( bEnd ){
-    int rc = sqlite3_exec(db, "END", 0, 0, 0);
-    if( check.rc==SQLITE_OK ) check.rc = rc;
+  /* 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;
   }
-  *pzReport = check.zReport;
-  return check.rc;
+  *peWithin = NOT_WITHIN;
 }
 
 /*
-** Usage:
-**
-**   rtreecheck(<rtree-table>);
-**   rtreecheck(<database>, <rtree-table>);
-**
-** Invoking this SQL function runs an integrity-check on the named rtree
-** table. The integrity-check verifies the following:
-**
-**   1. For each cell in the r-tree structure (%_node table), that:
-**
-**       a) for each dimension, (coord1 <= coord2).
-**
-**       b) unless the cell is on the root node, that the cell is bounded
-**          by the parent cell on the parent node.
-**
-**       c) for leaf nodes, that there is an entry in the %_rowid 
-**          table corresponding to the cell's rowid value that 
-**          points to the correct node.
-**
-**       d) for cells on non-leaf nodes, that there is an entry in the 
-**          %_parent table mapping from the cell's child node to the
-**          node that it resides on.
+** 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.
 **
-**   2. That there are the same number of entries in the %_rowid table
-**      as there are leaf cells in the r-tree structure, and that there
-**      is a leaf cell that corresponds to each entry in the %_rowid table.
+** The constraint is of the form:  xN op $val
 **
-**   3. That there are the same number of entries in the %_parent table
-**      as there are non-leaf cells in the r-tree structure, and that 
-**      there is a non-leaf cell that corresponds to each entry in the 
-**      %_parent table.
+** 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 rtreecheck(
-  sqlite3_context *ctx, 
-  int nArg, 
-  sqlite3_value **apArg
+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 */
 ){
-  if( nArg!=1 && nArg!=2 ){
-    sqlite3_result_error(ctx, 
-        "wrong number of arguments to function rtreecheck()", -1
-    );
-  }else{
-    int rc;
-    char *zReport = 0;
-    const char *zDb = (const char*)sqlite3_value_text(apArg[0]);
-    const char *zTab;
-    if( nArg==1 ){
-      zTab = zDb;
-      zDb = "main";
-    }else{
-      zTab = (const char*)sqlite3_value_text(apArg[1]);
-    }
-    rc = rtreeCheckTable(sqlite3_context_db_handle(ctx), zDb, zTab, &zReport);
-    if( rc==SQLITE_OK ){
-      sqlite3_result_text(ctx, zReport ? zReport : "ok", -1, SQLITE_TRANSIENT);
-    }else{
-      sqlite3_result_error_code(ctx, rc);
-    }
-    sqlite3_free(zReport);
+  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;
 }
 
-
 /*
-** Register the r-tree module with database handle db. This creates the
-** virtual table module "rtree" and the debugging/analysis scalar 
-** function "rtreenode".
+** 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.
 */
-SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db){
-  const int utf8 = SQLITE_UTF8;
-  int rc;
-
-  rc = sqlite3_create_function(db, "rtreenode", 2, utf8, 0, rtreenode, 0, 0);
-  if( rc==SQLITE_OK ){
-    rc = sqlite3_create_function(db, "rtreedepth", 1, utf8, 0,rtreedepth, 0, 0);
-  }
-  if( rc==SQLITE_OK ){
-    rc = sqlite3_create_function(db, "rtreecheck", -1, utf8, 0,rtreecheck, 0,0);
-  }
-  if( rc==SQLITE_OK ){
-#ifdef SQLITE_RTREE_INT_ONLY
-    void *c = (void *)RTREE_COORD_INT32;
-#else
-    void *c = (void *)RTREE_COORD_REAL32;
-#endif
-    rc = sqlite3_create_module_v2(db, "rtree", &rtreeModule, c, 0);
-  }
-  if( rc==SQLITE_OK ){
-    void *c = (void *)RTREE_COORD_INT32;
-    rc = sqlite3_create_module_v2(db, "rtree_i32", &rtreeModule, c, 0);
+static int nodeRowidIndex(
+  Rtree *pRtree, 
+  RtreeNode *pNode, 
+  i64 iRowid,
+  int *piIndex
+){
+  int ii;
+  int nCell = NCELL(pNode);
+  assert( nCell<200 );
+  for(ii=0; ii<nCell; ii++){
+    if( nodeGetRowid(pRtree, pNode, ii)==iRowid ){
+      *piIndex = ii;
+      return SQLITE_OK;
+    }
   }
-
-  return rc;
+  return SQLITE_CORRUPT_VTAB;
 }
 
 /*
-** This routine deletes the RtreeGeomCallback object that was attached
-** one of the SQL functions create by sqlite3_rtree_geometry_callback()
-** or sqlite3_rtree_query_callback().  In other words, this routine is the
-** destructor for an RtreeGeomCallback objecct.  This routine is called when
-** the corresponding SQL function is deleted.
+** Return the index of the cell containing a pointer to node pNode
+** in its parent. If pNode is the root node, return -1.
 */
-static void rtreeFreeCallback(void *p){
-  RtreeGeomCallback *pInfo = (RtreeGeomCallback*)p;
-  if( pInfo->xDestructor ) pInfo->xDestructor(pInfo->pContext);
-  sqlite3_free(p);
+static int nodeParentIndex(Rtree *pRtree, RtreeNode *pNode, int *piIndex){
+  RtreeNode *pParent = pNode->pParent;
+  if( pParent ){
+    return nodeRowidIndex(pRtree, pParent, pNode->iNode, piIndex);
+  }
+  *piIndex = -1;
+  return SQLITE_OK;
 }
 
 /*
-** This routine frees the BLOB that is returned by geomCallback().
+** 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 void rtreeMatchArgFree(void *pArg){
-  int i;
-  RtreeMatchArg *p = (RtreeMatchArg*)pArg;
-  for(i=0; i<p->nParam; i++){
-    sqlite3_value_free(p->apSqlParam[i]);
-  }
-  sqlite3_free(p);
+static int rtreeSearchPointCompare(
+  const RtreeSearchPoint *pA,
+  const RtreeSearchPoint *pB
+){
+  if( pA->rScore<pB->rScore ) return -1;
+  if( pA->rScore>pB->rScore ) return +1;
+  if( pA->iLevel<pB->iLevel ) return -1;
+  if( pA->iLevel>pB->iLevel ) return +1;
+  return 0;
 }
 
 /*
-** 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.
+** Interchange two search points in a cursor.
 */
-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->iSize = nBlob;
-    pBlob->cb = pGeomCtx[0];
-    pBlob->apSqlParam = (sqlite3_value**)&pBlob->aParam[nArg];
-    pBlob->nParam = nArg;
-    for(i=0; i<nArg; i++){
-      pBlob->apSqlParam[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);
+static void rtreeSearchPointSwap(RtreeCursor *p, int i, int j){
+  RtreeSearchPoint t = p->aPoint[i];
+  assert( i<j );
+  p->aPoint[i] = p->aPoint[j];
+  p->aPoint[j] = t;
+  i++; j++;
+  if( i<RTREE_CACHE_SZ ){
+    if( j>=RTREE_CACHE_SZ ){
+      nodeRelease(RTREE_OF_CURSOR(p), p->aNode[i]);
+      p->aNode[i] = 0;
     }else{
-      sqlite3_result_pointer(ctx, pBlob, "RtreeMatchArg", rtreeMatchArgFree);
+      RtreeNode *pTemp = p->aNode[i];
+      p->aNode[i] = p->aNode[j];
+      p->aNode[j] = pTemp;
     }
   }
 }
 
 /*
-** Register a new geometry function for use with the r-tree MATCH operator.
+** Return the search point with the lowest current score.
 */
-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 */
+static RtreeSearchPoint *rtreeSearchPointFirst(RtreeCursor *pCur){
+  return pCur->bPoint ? &pCur->sPoint : pCur->nPoint ? pCur->aPoint : 0;
+}
 
-  /* 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
-  );
+/*
+** 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];
 }
 
 /*
-** Register a new 2nd-generation geometry function for use with the
-** r-tree MATCH operator.
+** Push a new element onto the priority queue
 */
-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 */
+static RtreeSearchPoint *rtreeEnqueue(
+  RtreeCursor *pCur,    /* The cursor */
+  RtreeDValue rScore,   /* Score for the new search point */
+  u8 iLevel             /* Level for the new search point */
 ){
-  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
-  );
+  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;
 }
 
-#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.
+** 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( ii<RTREE_CACHE_SZ ){
+        assert( pCur->aNode[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 !defined(SQLITE_CORE)                  \
- || defined(SQLITE_ENABLE_ICU)             \
- || defined(SQLITE_ENABLE_ICU_COLLATIONS)
-
-/* Include ICU headers */
-#include <unicode/utypes.h>
-#include <unicode/uregex.h>
-#include <unicode/ustring.h>
-#include <unicode/ucol.h>
-
-/* #include <assert.h> */
-
-#ifndef SQLITE_CORE
-/*   #include "sqlite3ext.h" */
-  SQLITE_EXTENSION_INIT1
+#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( idx<RTREE_CACHE_SZ ){
+    printf(" %p\n", pCur->aNode[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; ii<pCur->nPoint; ii++){
+    if( ii>0 || pCur->bPoint ) printf("              ");
+    tracePoint(&pCur->aPoint[ii], ii, pCur);
+  }
+}
+# define RTREE_QUEUE_TRACE(A,B) traceQueue(A,B)
 #else
-/*   #include "sqlite3.h" */
+# define RTREE_QUEUE_TRACE(A,B)   /* no-op */
 #endif
 
-/*
-** 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.
+/* Remove the search point with the lowest current score.
 */
-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);
+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( n<RTREE_CACHE_SZ-1 ){
+      p->aNode[1] = p->aNode[n+1];
+      p->aNode[n+1] = 0;
+    }
+    i = 0;
+    while( (j = i*2+1)<n ){
+      k = j+1;
+      if( k<n && rtreeSearchPointCompare(&p->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;
+        }
+      }
+    }
+  }
 }
 
-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
 
 /*
-** Maximum length (in bytes) of the pattern in a LIKE or GLOB
-** operator.
+** 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.
 */
-#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH
-# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000
-#endif
+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;
 
-/*
-** Version of sqlite3_free() that is always a function, never a macro.
-*/
-static void xFree(void *p){
-  sqlite3_free(p);
+  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->iCell<nCell ){
+      sqlite3_rtree_dbl rScore = (sqlite3_rtree_dbl)-1;
+      u8 *pCellData = pNode->zData + (4+pRtree->nBytesPerCell*p->iCell);
+      eWithin = FULLY_WITHIN;
+      for(ii=0; ii<nConstraint; ii++){
+        RtreeConstraint *pConstraint = pCur->aConstraint + 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( rScore<RTREE_ZERO ) rScore = RTREE_ZERO;
+      p = rtreeSearchPointNew(pCur, rScore, x.iLevel);
+      if( p==0 ) return SQLITE_NOMEM;
+      p->eWithin = (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;
 }
 
-/*
-** 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.
+/* 
+** Rtree virtual table module xNext method.
 */
-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,
-};
+static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){
+  RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor;
+  int rc = SQLITE_OK;
 
-#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++));                      \
-    }                                                      \
+  /* Move to the next entry that matches the configured constraints. */
+  RTREE_QUEUE_TRACE(pCsr, "POP-Nx:");
+  if( pCsr->bAuxValid ){
+    pCsr->bAuxValid = 0;
+    sqlite3_reset(pCsr->pReadAux);
   }
+  rtreeSearchPointPop(pCsr);
+  rc = rtreeStepToLeaf(pCsr);
+  return rc;
+}
 
-#define SQLITE_ICU_SKIP_UTF8(zIn)                          \
-  assert( *zIn );                                          \
-  if( *(zIn++)>=0xc0 ){                                    \
-    while( (*zIn & 0xc0)==0x80 ){zIn++;}                   \
+/* 
+** 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;
+}
 
-
-/*
-** 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.
+/* 
+** Rtree virtual table module xColumn method.
 */
-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 uint32_t MATCH_ONE = (uint32_t)'_';
-  static const uint32_t MATCH_ALL = (uint32_t)'%';
-
-  int prevEscape = 0;     /* True if the previous character was uEsc */
-
-  while( 1 ){
-
-    /* Read (and consume) the next character from the input pattern. */
-    uint32_t 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;
+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);
 
-      /* 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( rc ) return rc;
+  if( p==0 ) return SQLITE_OK;
+  if( i==0 ){
+    sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell));
+  }else if( i<=pRtree->nDim2 ){
+    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);
+    }
+  }else{
+    if( !pCsr->bAuxValid ){
+      if( pCsr->pReadAux==0 ){
+        rc = sqlite3_prepare_v3(pRtree->db, pRtree->zReadAuxSql, -1, 0,
+                                &pCsr->pReadAux, 0);
+        if( rc ) return rc;
       }
-
-      if( *zPattern==0 ) return 1;
-
-      while( *zString ){
-        if( icuLikeCompare(zPattern, zString, uEsc) ){
-          return 1;
-        }
-        SQLITE_ICU_SKIP_UTF8(zString);
+      sqlite3_bind_int64(pCsr->pReadAux, 1, 
+          nodeGetRowid(pRtree, pNode, p->iCell));
+      rc = sqlite3_step(pCsr->pReadAux);
+      if( rc==SQLITE_ROW ){
+        pCsr->bAuxValid = 1;
+      }else{
+        sqlite3_reset(pCsr->pReadAux);
+        if( rc==SQLITE_DONE ) rc = SQLITE_OK;
+        return rc;
       }
-      return 0;
+    }
+    sqlite3_result_value(ctx,
+         sqlite3_column_value(pCsr->pReadAux, i - pRtree->nDim2 + 1));
+  }  
+  return SQLITE_OK;
+}
 
-    }else if( !prevEscape && uPattern==MATCH_ONE ){
-      /* Case 2. */
-      if( *zString==0 ) return 0;
-      SQLITE_ICU_SKIP_UTF8(zString);
+/* 
+** 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;
+}
 
-    }else if( !prevEscape && uPattern==(uint32_t)uEsc){
-      /* Case 3. */
-      prevEscape = 1;
+/*
+** 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, *pSrc;       /* BLOB returned by geometry function */
+  sqlite3_rtree_query_info *pInfo;   /* Callback information */
 
-    }else{
-      /* Case 4. */
-      uint32_t uString;
-      SQLITE_ICU_READ_UTF8(zString, uString);
-      uString = (uint32_t)u_foldCase((UChar32)uString, U_FOLD_CASE_DEFAULT);
-      uPattern = (uint32_t)u_foldCase((UChar32)uPattern, U_FOLD_CASE_DEFAULT);
-      if( uString!=uPattern ){
-        return 0;
-      }
-      prevEscape = 0;
-    }
-  }
+  pSrc = sqlite3_value_pointer(pValue, "RtreeMatchArg");
+  if( pSrc==0 ) return SQLITE_ERROR;
+  pInfo = (sqlite3_rtree_query_info*)
+                sqlite3_malloc64( sizeof(*pInfo)+pSrc->iSize );
+  if( !pInfo ) return SQLITE_NOMEM;
+  memset(pInfo, 0, sizeof(*pInfo));
+  pBlob = (RtreeMatchArg*)&pInfo[1];
+  memcpy(pBlob, pSrc, pSrc->iSize);
+  pInfo->pContext = pBlob->cb.pContext;
+  pInfo->nParam = pBlob->nParam;
+  pInfo->aParam = pBlob->aParam;
+  pInfo->apSqlParam = pBlob->apSqlParam;
 
-  return *zString==0;
+  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;
 }
 
-/*
-** 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).
+/* 
+** Rtree virtual table module xFilter method.
 */
-static void icuLikeFunc(
-  sqlite3_context *context
-  int argc, 
-  sqlite3_value **argv
+static int rtreeFilter(
+  sqlite3_vtab_cursor *pVtabCursor
+  int idxNum, const char *idxStr,
+  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;
+  Rtree *pRtree = (Rtree *)pVtabCursor->pVtab;
+  RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor;
+  RtreeNode *pRoot = 0;
+  int ii;
+  int rc = SQLITE_OK;
+  int iCell = 0;
+  sqlite3_stmt *pStmt;
 
-  /* 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;
-  }
+  rtreeReference(pRtree);
 
+  /* Reset the cursor to the same state as rtreeOpen() leaves it in. */
+  freeCursorConstraints(pCsr);
+  sqlite3_free(pCsr->aPoint);
+  pStmt = pCsr->pReadAux;
+  memset(pCsr, 0, sizeof(RtreeCursor));
+  pCsr->base.pVtab = (sqlite3_vtab*)pRtree;
+  pCsr->pReadAux = pStmt;
 
-  if( argc==3 ){
-    /* The escape character string must consist of a single UTF-8 character.
-    ** Otherwise, return an error.
+  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. 
     */
-    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;
+    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; ii<argc; ii++){
+          RtreeConstraint *p = &pCsr->aConstraint[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);
     }
   }
 
-  if( zA && zB ){
-    sqlite3_result_int(context, icuLikeCompare(zA, zB, uEsc));
-  }
-}
-
-/*
-** 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);
+  nodeRelease(pRtree, pRoot);
+  rtreeRelease(pRtree);
+  return rc;
 }
 
 /*
-** 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.
+** Rtree virtual table module xBestIndex method. There are three
+** table scan strategies to choose from (in order from most to 
+** least desirable):
 **
-** SQLite maps the regexp() function to the regexp() operator such
-** that the following two are equivalent:
+**   idxNum     idxStr        Strategy
+**   ------------------------------------------------
+**     1        Unused        Direct lookup by rowid.
+**     2        See below     R-tree query or full-table scan.
+**   ------------------------------------------------
 **
-**     zString REGEXP zPattern
-**     regexp(zPattern, zString)
+** 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.
 **
-** Uses the following ICU regexp APIs:
+** The first of each pair of bytes in idxStr identifies the constraint
+** operator as follows:
 **
-**     uregex_open()
-**     uregex_matches()
-**     uregex_close()
+**   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 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]);
+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 */
 
-  (void)nArg;  /* Unused parameter */
+  int iIdx = 0;
+  char zIdxStr[RTREE_MAX_DIMENSIONS*8+1];
+  memset(zIdxStr, 0, sizeof(zIdxStr));
 
-  /* If the left hand side of the regexp operator is NULL, 
-  ** then the result is also NULL. 
-  */
-  if( !zString ){
-    return;
+  /* 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; ii<pIdxInfo->nConstraint; ii++){
+    if( pIdxInfo->aConstraint[ii].op==SQLITE_INDEX_CONSTRAINT_MATCH ){
+      bMatch = 1;
+    }
   }
 
-  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);
+  assert( pIdxInfo->idxStr==0 );
+  for(ii=0; ii<pIdxInfo->nConstraint && iIdx<(int)(sizeof(zIdxStr)-1); ii++){
+    struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];
 
-    if( U_SUCCESS(status) ){
-      sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete);
-    }else{
-      assert(!pExpr);
-      icuFunctionError(p, "uregex_open", status);
-      return;
+    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; jj<ii; jj++){
+        pIdxInfo->aConstraintUsage[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;
+      pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
+      return SQLITE_OK;
     }
-  }
 
-  /* 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;
+    if( p->usable
+    && ((p->iColumn>0 && p->iColumn<=pRtree->nDim2)
+        || 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;
+    }
   }
 
-  /* Attempt the match */
-  res = uregex_matches(pExpr, 0, &status);
-  if( !U_SUCCESS(status) ){
-    icuFunctionError(p, "uregex_matches", status);
-    return;
+  pIdxInfo->idxNum = 2;
+  pIdxInfo->needToFreeIdxStr = 1;
+  if( iIdx>0 && 0==(pIdxInfo->idxStr = sqlite3_mprintf("%s", zIdxStr)) ){
+    return SQLITE_NOMEM;
   }
 
-  /* 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);
+  nRow = pRtree->nRowEst >> (iIdx/2);
+  pIdxInfo->estimatedCost = (double)6.0 * (double)nRow;
+  pIdxInfo->estimatedRows = nRow;
 
-  /* Return 1 or 0. */
-  sqlite3_result_int(p, res ? 1 : 0);
+  return rc;
 }
 
 /*
-** 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
+** Return the N-dimensional volumn of the cell stored in *p.
 */
-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);
+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;
     }
-
-    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);
+  }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;
   }
-  assert( 0 );     /* Unreachable */
+  return area;
 }
 
-#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
-
 /*
-** Collation sequence destructor function. The pCtx argument points to
-** a UCollator structure previously allocated using ucol_open().
+** Return the margin length of cell p. The margin length is the sum
+** of the objects size in each dimension.
 */
-static void icuCollationDel(void *pCtx){
-  UCollator *p = (UCollator *)pCtx;
-  ucol_close(p);
+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;
 }
 
 /*
-** Collation sequence comparison function. The pCtx argument points to
-** a UCollator structure previously allocated using ucol_open().
+** Store the union of cells p1 and p2 in p1.
 */
-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;
+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( ii<pRtree->nDim2 );
+  }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( ii<pRtree->nDim2 );
   }
-  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(<locale>, <collation-name>);
-**
-** Where <locale> is a string containing an ICU locale identifier (i.e.
-** "en_AU", "tr_TR" etc.) and <collation-name> is the name of the
-** collation sequence to create.
+** Return true if the area covered by p2 is a subset of the area covered
+** by p1. False otherwise.
 */
-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;
+static int cellContains(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
+  int ii;
+  int isInt = (pRtree->eCoordType==RTREE_COORD_INT32);
+  for(ii=0; ii<pRtree->nDim2; ii+=2){
+    RtreeCoord *a1 = &p1->aCoord[ii];
+    RtreeCoord *a2 = &p2->aCoord[ii];
+    if( (!isInt && (a2[0].f<a1[0].f || a2[1].f>a1[1].f)) 
+     || ( isInt && (a2[0].i<a1[0].i || a2[1].i>a1[1].i)) 
+    ){
+      return 0;
+    }
   }
+  return 1;
+}
 
-  pUCollator = ucol_open(zLocale, &status);
-  if( !U_SUCCESS(status) ){
-    icuFunctionError(p, "ucol_open", status);
-    return;
-  }
-  assert(p);
+/*
+** 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);
+}
 
-  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);
+static RtreeDValue cellOverlap(
+  Rtree *pRtree, 
+  RtreeCell *p, 
+  RtreeCell *aCell, 
+  int nCell
+){
+  int ii;
+  RtreeDValue overlap = RTREE_ZERO;
+  for(ii=0; ii<nCell; ii++){
+    int jj;
+    RtreeDValue o = (RtreeDValue)1;
+    for(jj=0; jj<pRtree->nDim2; 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( x2<x1 ){
+        o = (RtreeDValue)0;
+        break;
+      }else{
+        o = o * (x2-x1);
+      }
+    }
+    overlap += o;
   }
+  return overlap;
 }
 
+
 /*
-** Register the ICU extension functions with database db.
+** This function implements the ChooseLeaf algorithm from Gutman[84].
+** ChooseSubTree in r*tree terminology.
 */
-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},
-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
-    {"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},
-#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
-  };
-  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
-    );
+static int ChooseLeaf(
+  Rtree *pRtree,               /* Rtree table */
+  RtreeCell *pCell,            /* Cell to insert into rtree */
+  int iHeight,                 /* Height of sub-tree rooted at pCell */
+  RtreeNode **ppLeaf           /* OUT: Selected leaf page */
+){
+  int rc;
+  int ii;
+  RtreeNode *pNode = 0;
+  rc = nodeAcquire(pRtree, 1, 0, &pNode);
+
+  for(ii=0; rc==SQLITE_OK && ii<(pRtree->iDepth-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; iCell<nCell; iCell++){
+      int bBest = 0;
+      RtreeDValue growth;
+      RtreeDValue area;
+      nodeGetCell(pRtree, pNode, iCell, &cell);
+      growth = cellGrowth(pRtree, &cell, pCell);
+      area = cellArea(pRtree, &cell);
+      if( iCell==0||growth<fMinGrowth||(growth==fMinGrowth && area<fMinArea) ){
+        bBest = 1;
+      }
+      if( bBest ){
+        fMinGrowth = growth;
+        fMinArea = area;
+        iBest = cell.iRowid;
+      }
+    }
+
+    sqlite3_free(aCell);
+    rc = nodeAcquire(pRtree, iBest, pNode, &pChild);
+    nodeRelease(pRtree, pNode);
+    pNode = pChild;
   }
 
+  *ppLeaf = pNode;
   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
+/*
+** A cell with the same content as pCell has just been inserted into
+** the node pNode. This function updates the bounding box cells in
+** all ancestor elements.
+*/
+static int AdjustTree(
+  Rtree *pRtree,                    /* Rtree table */
+  RtreeNode *pNode,                 /* Adjust ancestry of this node. */
+  RtreeCell *pCell                  /* This cell was just inserted */
 ){
-  SQLITE_EXTENSION_INIT2(pApi)
-  return sqlite3IcuInit(db);
+  RtreeNode *p = pNode;
+  while( p->pParent ){
+    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;
 }
-#endif
 
-#endif
+/*
+** Write mapping (iRowid->iNode) to the <rtree>_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);
+}
 
-/************** End of icu.c *************************************************/
-/************** Begin file fts3_icu.c ****************************************/
 /*
-** 2007 June 22
+** Write mapping (iNode->iPar) to the <rtree>_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:
 **
-** The author disclaims copyright to this source code.  In place of
-** a legal notice, here is a blessing:
+**   aIdx      = { 0,   1,   2,   3 }
+**   aDistance = { 5.0, 2.0, 7.0, 6.0 }
 **
-**    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 function sets the aIdx array to contain:
 **
-*************************************************************************
-** This file implements a tokenizer for fts3 based on the ICU library.
+**   aIdx      = { 0,   1,   2,   3 }
+**
+** The aSpare array is used as temporary working space by the
+** sorting algorithm.
 */
-/* #include "fts3Int.h" */
-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
-#ifdef SQLITE_ENABLE_ICU
+static void SortByDistance(
+  int *aIdx, 
+  int nIdx, 
+  RtreeDValue *aDistance, 
+  int *aSpare
+){
+  if( nIdx>1 ){
+    int iLeft = 0;
+    int iRight = 0;
 
-/* #include <assert.h> */
-/* #include <string.h> */
-/* #include "fts3_tokenizer.h" */
+    int nLeft = nIdx/2;
+    int nRight = nIdx-nLeft;
+    int *aLeft = aIdx;
+    int *aRight = &aIdx[nLeft];
 
-#include <unicode/ubrk.h>
-/* #include <unicode/ucol.h> */
-/* #include <unicode/ustring.h> */
-#include <unicode/utf16.h>
+    SortByDistance(aLeft, nLeft, aDistance, aSpare);
+    SortByDistance(aRight, nRight, aDistance, aSpare);
 
-typedef struct IcuTokenizer IcuTokenizer;
-typedef struct IcuCursor IcuCursor;
+    memcpy(aSpare, aLeft, sizeof(int)*nLeft);
+    aLeft = aSpare;
 
-struct IcuTokenizer {
-  sqlite3_tokenizer base;
-  char *zLocale;
-};
+    while( iLeft<nLeft || iRight<nRight ){
+      if( iLeft==nLeft ){
+        aIdx[iLeft+iRight] = aRight[iRight];
+        iRight++;
+      }else if( iRight==nRight ){
+        aIdx[iLeft+iRight] = aLeft[iLeft];
+        iLeft++;
+      }else{
+        RtreeDValue fLeft = aDistance[aLeft[iLeft]];
+        RtreeDValue fRight = aDistance[aRight[iRight]];
+        if( fLeft<fRight ){
+          aIdx[iLeft+iRight] = aLeft[iLeft];
+          iLeft++;
+        }else{
+          aIdx[iLeft+iRight] = aRight[iRight];
+          iRight++;
+        }
+      }
+    }
 
-struct IcuCursor {
-  sqlite3_tokenizer_cursor base;
+#if 0
+    /* Check that the sort worked */
+    {
+      int jj;
+      for(jj=1; jj<nIdx; jj++){
+        RtreeDValue left = aDistance[aIdx[jj-1]];
+        RtreeDValue right = aDistance[aIdx[jj]];
+        assert( left<=right );
+      }
+    }
+#endif
+  }
+}
 
-  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 */
+/*
+** Arguments aIdx, aCell 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 dimension iDim of the cells in aCell. The
+** minimum value of dimension iDim is considered first, the
+** maximum used to break ties.
+**
+** The aSpare array is used as temporary working space by the
+** sorting algorithm.
+*/
+static void SortByDimension(
+  Rtree *pRtree,
+  int *aIdx, 
+  int nIdx, 
+  int iDim, 
+  RtreeCell *aCell, 
+  int *aSpare
+){
+  if( nIdx>1 ){
 
-  int nBuffer;
-  char *zBuffer;
+    int iLeft = 0;
+    int iRight = 0;
 
-  int iToken;
-};
+    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( iLeft<nLeft || iRight<nRight ){
+      RtreeDValue xleft1 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2]);
+      RtreeDValue xleft2 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2+1]);
+      RtreeDValue xright1 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2]);
+      RtreeDValue xright2 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2+1]);
+      if( (iLeft!=nLeft) && ((iRight==nRight)
+       || (xleft1<xright1)
+       || (xleft1==xright1 && xleft2<xright2)
+      )){
+        aIdx[iLeft+iRight] = aLeft[iLeft];
+        iLeft++;
+      }else{
+        aIdx[iLeft+iRight] = aRight[iRight];
+        iRight++;
+      }
+    }
+
+#if 0
+    /* Check that the sort worked */
+    {
+      int jj;
+      for(jj=1; jj<nIdx; jj++){
+        RtreeDValue xleft1 = aCell[aIdx[jj-1]].aCoord[iDim*2];
+        RtreeDValue xleft2 = aCell[aIdx[jj-1]].aCoord[iDim*2+1];
+        RtreeDValue xright1 = aCell[aIdx[jj]].aCoord[iDim*2];
+        RtreeDValue xright2 = aCell[aIdx[jj]].aCoord[iDim*2+1];
+        assert( xleft1<=xright1 && (xleft1<xright1 || xleft2<=xright2) );
+      }
+    }
+#endif
+  }
+}
 
 /*
-** Create a new tokenizer instance.
+** Implementation of the R*-tree variant of SplitNode from Beckman[1990].
 */
-static int icuCreate(
-  int argc,                            /* Number of entries in argv[] */
-  const char * const *argv,            /* Tokenizer creation arguments */
-  sqlite3_tokenizer **ppTokenizer      /* OUT: Created tokenizer */
+static int splitNodeStartree(
+  Rtree *pRtree,
+  RtreeCell *aCell,
+  int nCell,
+  RtreeNode *pLeft,
+  RtreeNode *pRight,
+  RtreeCell *pBboxLeft,
+  RtreeCell *pBboxRight
 ){
-  IcuTokenizer *p;
-  int n = 0;
+  int **aaSorted;
+  int *aSpare;
+  int ii;
 
-  if( argc>0 ){
-    n = strlen(argv[0])+1;
-  }
-  p = (IcuTokenizer *)sqlite3_malloc(sizeof(IcuTokenizer)+n);
-  if( !p ){
+  int iBestDim = 0;
+  int iBestSplit = 0;
+  RtreeDValue fBestMargin = RTREE_ZERO;
+
+  int nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int));
+
+  aaSorted = (int **)sqlite3_malloc(nByte);
+  if( !aaSorted ){
     return SQLITE_NOMEM;
   }
-  memset(p, 0, sizeof(IcuTokenizer));
 
-  if( n ){
-    p->zLocale = (char *)&p[1];
-    memcpy(p->zLocale, argv[0], n);
+  aSpare = &((int *)&aaSorted[pRtree->nDim])[pRtree->nDim*nCell];
+  memset(aaSorted, 0, nByte);
+  for(ii=0; ii<pRtree->nDim; ii++){
+    int jj;
+    aaSorted[ii] = &((int *)&aaSorted[pRtree->nDim])[ii*nCell];
+    for(jj=0; jj<nCell; jj++){
+      aaSorted[ii][jj] = jj;
+    }
+    SortByDimension(pRtree, aaSorted[ii], nCell, ii, aCell, aSpare);
   }
 
-  *ppTokenizer = (sqlite3_tokenizer *)p;
+  for(ii=0; ii<pRtree->nDim; 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( kk<nLeft ){
+          cellUnion(pRtree, &left, &aCell[aaSorted[ii][kk]]);
+        }else{
+          cellUnion(pRtree, &right, &aCell[aaSorted[ii][kk]]);
+        }
+      }
+      margin += cellMargin(pRtree, &left);
+      margin += cellMargin(pRtree, &right);
+      overlap = cellOverlap(pRtree, &left, &right, 1);
+      area = cellArea(pRtree, &left) + cellArea(pRtree, &right);
+      if( (nLeft==RTREE_MINCELLS(pRtree))
+       || (overlap<fBestOverlap)
+       || (overlap==fBestOverlap && area<fBestArea)
+      ){
+        iBestLeft = nLeft;
+        fBestOverlap = overlap;
+        fBestArea = area;
+      }
+    }
+
+    if( ii==0 || margin<fBestMargin ){
+      iBestDim = ii;
+      fBestMargin = margin;
+      iBestSplit = iBestLeft;
+    }
+  }
+
+  memcpy(pBboxLeft, &aCell[aaSorted[iBestDim][0]], sizeof(RtreeCell));
+  memcpy(pBboxRight, &aCell[aaSorted[iBestDim][iBestSplit]], sizeof(RtreeCell));
+  for(ii=0; ii<nCell; ii++){
+    RtreeNode *pTarget = (ii<iBestSplit)?pLeft:pRight;
+    RtreeCell *pBbox = (ii<iBestSplit)?pBboxLeft:pBboxRight;
+    RtreeCell *pCell = &aCell[aaSorted[iBestDim][ii]];
+    nodeInsertCell(pRtree, pTarget, pCell);
+    cellUnion(pRtree, pBbox, pCell);
+  }
 
+  sqlite3_free(aaSorted);
   return SQLITE_OK;
 }
 
-/*
-** Destroy a tokenizer
-*/
-static int icuDestroy(sqlite3_tokenizer *pTokenizer){
-  IcuTokenizer *p = (IcuTokenizer *)pTokenizer;
-  sqlite3_free(p);
-  return SQLITE_OK;
+
+static int updateMapping(
+  Rtree *pRtree, 
+  i64 iRowid, 
+  RtreeNode *pNode, 
+  int iHeight
+){
+  int (*xSetMapping)(Rtree *, sqlite3_int64, sqlite3_int64);
+  xSetMapping = ((iHeight==0)?rowidWrite:parentWrite);
+  if( iHeight>0 ){
+    RtreeNode *pChild = nodeHashLookup(pRtree, iRowid);
+    if( pChild ){
+      nodeRelease(pRtree, pChild->pParent);
+      nodeReference(pNode);
+      pChild->pParent = pNode;
+    }
+  }
+  return xSetMapping(pRtree, iRowid, pNode->iNode);
 }
 
-/*
-** 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 */
+static int SplitNode(
+  Rtree *pRtree,
+  RtreeNode *pNode,
+  RtreeCell *pCell,
+  int iHeight
 ){
-  IcuTokenizer *p = (IcuTokenizer *)pTokenizer;
-  IcuCursor *pCsr;
+  int i;
+  int newCellIsRight = 0;
 
-  const int32_t opt = U_FOLD_CASE_DEFAULT;
-  UErrorCode status = U_ZERO_ERROR;
-  int nChar;
+  int rc = SQLITE_OK;
+  int nCell = NCELL(pNode);
+  RtreeCell *aCell;
+  int *aiUsed;
 
-  UChar32 c;
-  int iInput = 0;
-  int iOut = 0;
+  RtreeNode *pLeft = 0;
+  RtreeNode *pRight = 0;
 
-  *ppCursor = 0;
+  RtreeCell leftbbox;
+  RtreeCell rightbbox;
 
-  if( zInput==0 ){
-    nInput = 0;
-    zInput = "";
-  }else if( nInput<0 ){
-    nInput = strlen(zInput);
+  /* 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;
   }
-  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;
+  aiUsed = (int *)&aCell[nCell+1];
+  memset(aiUsed, 0, sizeof(int)*(nCell+1));
+  for(i=0; i<nCell; i++){
+    nodeGetCell(pRtree, pNode, i, &aCell[i]);
   }
-  memset(pCsr, 0, sizeof(IcuCursor));
-  pCsr->aChar = (UChar *)&pCsr[1];
-  pCsr->aOffset = (int *)&pCsr->aChar[(nChar+3)&~3];
+  nodeZero(pRtree, pNode);
+  memcpy(&aCell[nCell], pCell, sizeof(RtreeCell));
+  nCell++;
 
-  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;
+  if( pNode->iNode==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);
+    pLeft->nRef++;
+  }
+
+  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;
     }
-    pCsr->aOffset[iOut] = iInput;
+  }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;
+  }
 
-    if( iInput<nInput ){
-      U8_NEXT(zInput, iInput, nInput, c);
-    }else{
-      c = 0;
+  for(i=0; i<NCELL(pRight); i++){
+    i64 iRowid = nodeGetRowid(pRtree, pRight, i);
+    rc = updateMapping(pRtree, iRowid, pRight, iHeight);
+    if( iRowid==pCell->iRowid ){
+      newCellIsRight = 1;
     }
+    if( rc!=SQLITE_OK ){
+      goto splitnode_out;
+    }
+  }
+  if( pNode->iNode==1 ){
+    for(i=0; i<NCELL(pLeft); i++){
+      i64 iRowid = nodeGetRowid(pRtree, pLeft, i);
+      rc = updateMapping(pRtree, iRowid, pLeft, iHeight);
+      if( rc!=SQLITE_OK ){
+        goto splitnode_out;
+      }
+    }
+  }else if( newCellIsRight==0 ){
+    rc = updateMapping(pRtree, pCell->iRowid, pLeft, iHeight);
   }
 
-  pCsr->pIter = ubrk_open(UBRK_WORD, p->zLocale, pCsr->aChar, iOut, &status);
-  if( !U_SUCCESS(status) ){
-    sqlite3_free(pCsr);
-    return SQLITE_ERROR;
+  if( rc==SQLITE_OK ){
+    rc = nodeRelease(pRtree, pRight);
+    pRight = 0;
+  }
+  if( rc==SQLITE_OK ){
+    rc = nodeRelease(pRtree, pLeft);
+    pLeft = 0;
   }
-  pCsr->nChar = iOut;
 
-  ubrk_first(pCsr->pIter);
-  *ppCursor = (sqlite3_tokenizer_cursor *)pCsr;
-  return SQLITE_OK;
+splitnode_out:
+  nodeRelease(pRtree, pRight);
+  nodeRelease(pRtree, pLeft);
+  sqlite3_free(aCell);
+  return rc;
 }
 
 /*
-** Close a tokenization cursor previously opened by a call to icuOpen().
+** 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 icuClose(sqlite3_tokenizer_cursor *pCursor){
-  IcuCursor *pCsr = (IcuCursor *)pCursor;
-  ubrk_close(pCsr->pIter);
-  sqlite3_free(pCsr->zBuffer);
-  sqlite3_free(pCsr);
+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; ii<nCell; ii++){
+      RtreeCell cell;
+      nodeGetCell(pRtree, pNode, ii, &cell);
+      cellUnion(pRtree, &box, &cell);
+    }
+    box.iRowid = pNode->iNode;
+    rc = nodeParentIndex(pRtree, pNode, &ii);
+    if( rc==SQLITE_OK ){
+      nodeOverwriteCell(pRtree, pParent, &box, ii);
+      rc = fixBoundingBox(pRtree, pParent);
+    }
+  }
+  return rc;
+}
+
 /*
-** Extract the next token from a tokenization cursor.
+** Delete the cell at index iCell of node pNode. After removing the
+** cell, adjust the r-tree data structure if required.
 */
-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 */
+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)<RTREE_MINCELLS(pRtree) ){
+      rc = removeNode(pRtree, pNode, iHeight);
+    }else{
+      rc = fixBoundingBox(pRtree, pNode);
+    }
+  }
+
+  return rc;
+}
+
+static int Reinsert(
+  Rtree *pRtree, 
+  RtreeNode *pNode, 
+  RtreeCell *pCell, 
+  int iHeight
 ){
-  IcuCursor *pCsr = (IcuCursor *)pCursor;
+  int *aOrder;
+  int *aSpare;
+  RtreeCell *aCell;
+  RtreeDValue *aDistance;
+  int nCell;
+  RtreeDValue aCenterCoord[RTREE_MAX_DIMENSIONS];
+  int iDim;
+  int ii;
+  int rc = SQLITE_OK;
+  int n;
 
-  int iStart = 0;
-  int iEnd = 0;
-  int nByte = 0;
+  memset(aCenterCoord, 0, sizeof(RtreeDValue)*RTREE_MAX_DIMENSIONS);
 
-  while( iStart==iEnd ){
-    UChar32 c;
+  nCell = NCELL(pNode)+1;
+  n = (nCell+1)&(~1);
 
-    iStart = ubrk_current(pCsr->pIter);
-    iEnd = ubrk_next(pCsr->pIter);
-    if( iEnd==UBRK_DONE ){
-      return SQLITE_DONE;
+  /* Allocate the buffers used by this operation. The allocation is
+  ** relinquished before this function returns.
+  */
+  aCell = (RtreeCell *)sqlite3_malloc(n * (
+    sizeof(RtreeCell)     +         /* aCell array */
+    sizeof(int)           +         /* aOrder array */
+    sizeof(int)           +         /* aSpare array */
+    sizeof(RtreeDValue)             /* aDistance array */
+  ));
+  if( !aCell ){
+    return SQLITE_NOMEM;
+  }
+  aOrder    = (int *)&aCell[n];
+  aSpare    = (int *)&aOrder[n];
+  aDistance = (RtreeDValue *)&aSpare[n];
+
+  for(ii=0; ii<nCell; ii++){
+    if( ii==(nCell-1) ){
+      memcpy(&aCell[ii], pCell, sizeof(RtreeCell));
+    }else{
+      nodeGetCell(pRtree, pNode, ii, &aCell[ii]);
     }
+    aOrder[ii] = ii;
+    for(iDim=0; iDim<pRtree->nDim; iDim++){
+      aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2]);
+      aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2+1]);
+    }
+  }
+  for(iDim=0; iDim<pRtree->nDim; iDim++){
+    aCenterCoord[iDim] = (aCenterCoord[iDim]/(nCell*(RtreeDValue)2));
+  }
 
-    while( iStart<iEnd ){
-      int iWhite = iStart;
-      U16_NEXT(pCsr->aChar, iWhite, pCsr->nChar, c);
-      if( u_isspace(c) ){
-        iStart = iWhite;
+  for(ii=0; ii<nCell; ii++){
+    aDistance[ii] = RTREE_ZERO;
+    for(iDim=0; iDim<pRtree->nDim; iDim++){
+      RtreeDValue coord = (DCOORD(aCell[ii].aCoord[iDim*2+1]) - 
+                               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{
-        break;
+        rc = parentWrite(pRtree, p->iRowid, pNode->iNode);
+      }
+    }
+  }
+  if( rc==SQLITE_OK ){
+    rc = fixBoundingBox(pRtree, pNode);
+  }
+  for(; rc==SQLITE_OK && ii<nCell; ii++){
+    /* Find a node to store this cell in. pNode->iNode 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;
       }
     }
-    assert(iStart<=iEnd);
   }
 
-  do {
-    UErrorCode status = U_ZERO_ERROR;
-    if( nByte ){
-      char *zNew = sqlite3_realloc(pCsr->zBuffer, nByte);
-      if( !zNew ){
-        return SQLITE_NOMEM;
+  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);
       }
-      pCsr->zBuffer = zNew;
-      pCsr->nBuffer = nByte;
     }
+  }
+  return rc;
+}
 
-    u_strToUTF8(
-        pCsr->zBuffer, pCsr->nBuffer, &nByte,    /* Output vars */
-        &pCsr->aChar[iStart], iEnd-iStart,       /* Input vars */
-        &status                                  /* Output success/failure */
-    );
-  } while( nByte>pCsr->nBuffer );
+static int reinsertNodeContent(Rtree *pRtree, RtreeNode *pNode){
+  int ii;
+  int rc = SQLITE_OK;
+  int nCell = NCELL(pNode);
 
-  *ppToken = pCsr->zBuffer;
-  *pnBytes = nByte;
-  *piStartOffset = pCsr->aOffset[iStart];
-  *piEndOffset = pCsr->aOffset[iEnd];
-  *piPosition = pCsr->iToken++;
+  for(ii=0; rc==SQLITE_OK && ii<nCell; ii++){
+    RtreeNode *pInsert;
+    RtreeCell cell;
+    nodeGetCell(pRtree, pNode, ii, &cell);
 
-  return SQLITE_OK;
+    /* Find a node to store this cell in. pNode->iNode 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;
 }
 
 /*
-** The set of routines that implement the simple tokenizer
+** Select a currently unused rowid for a new r-tree record.
 */
-static const sqlite3_tokenizer_module icuTokenizerModule = {
-  0,                           /* iVersion    */
-  icuCreate,                   /* xCreate     */
-  icuDestroy,                  /* xCreate     */
-  icuOpen,                     /* xOpen       */
-  icuClose,                    /* xClose      */
-  icuNext,                     /* xNext       */
-  0,                           /* xLanguageid */
-};
+static int rtreeNewRowid(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;
+}
 
 /*
-** Set *ppModule to point at the implementation of the ICU tokenizer.
+** Remove the entry with rowid=iDelete from the r-tree structure.
 */
-SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
-  sqlite3_tokenizer_module const**ppModule
-){
-  *ppModule = &icuTokenizerModule;
-}
+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 = 0;           /* Root node of rtree structure */
 
-#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 "<database>-oal" instead of "<database>-wal".
-**     Because regular SQLite clients do not look for file named
-**     "<database>-oal", they go on using the original database in
-**     rollback mode while the *-oal file is being generated.
-** 
-**     During this stage RBU does not update the database by writing
-**     directly to the target tables. Instead it creates "imposter"
-**     tables using the SQLITE_TESTCTRL_IMPOSTER interface that it uses
-**     to update each b-tree individually. All updates required by each
-**     b-tree are completed before moving on to the next, and all
-**     updates are done in sorted key order.
-** 
-**  2) The "<database>-oal" file is moved to the equivalent "<database>-wal"
-**     location using a call to rename(2). Before doing this the RBU
-**     module takes an EXCLUSIVE lock on the database file, ensuring
-**     that there are no other active readers.
-** 
-**     Once the EXCLUSIVE lock is released, any other database readers
-**     detect the new *-wal file and read the database in wal mode. At
-**     this point they see the new version of the database - including
-**     the updates made as part of the RBU update.
-** 
-**  3) The new *-wal file is checkpointed. This proceeds in the same way 
-**     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).
+  /* 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 <rtree>_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 = 0;
+    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;
+    pRtree->nNodeRef--;
+    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( f<d ){
+    f = (float)(d*(d<0 ? RNDTOWARDS : RNDAWAY));
+  }
+  return f;
+}
+#endif /* !defined(SQLITE_RTREE_INT_ONLY) */
+
+/*
+** A constraint has failed while inserting a row into an rtree table. 
+** Assuming no OOM error occurs, this function sets the error message 
+** (at pRtree->base.zErrMsg) to an appropriate value and returns
+** SQLITE_CONSTRAINT.
 **
-**  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.
+** 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.
 **
-**  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.
-** 
+** 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);
+}
 
-/* #include <assert.h> */
-/* #include <string.h> */
-/* #include <stdio.h> */
 
-/* #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. 
+** The xUpdate method for rtree module virtual tables.
 */
+static int rtreeUpdate(
+  sqlite3_vtab *pVtab, 
+  int nData, 
+  sqlite3_value **aData, 
+  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 */
+
+  if( pRtree->nNodeRef ){
+    /* Unable to write to the btree while another cursor is reading from it,
+    ** since the write might do a rebalance which would disrupt the read
+    ** cursor. */
+    return SQLITE_LOCKED_VTAB;
+  }
+  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;
+    int nn = nData - 4;
+
+    if( nn > pRtree->nDim2 ) nn = pRtree->nDim2;
+    /* Populate the cell.aCoord[] array. The first coordinate is aData[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.
+    */
+
+#ifndef SQLITE_RTREE_INT_ONLY
+    if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
+      for(ii=0; ii<nn; ii+=2){
+        cell.aCoord[ii].f = rtreeValueDown(aData[ii+3]);
+        cell.aCoord[ii+1].f = rtreeValueUp(aData[ii+4]);
+        if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){
+          rc = rtreeConstraintError(pRtree, ii+1);
+          goto constraint;
+        }
+      }
+    }else
+#endif
+    {
+      for(ii=0; ii<nn; ii+=2){
+        cell.aCoord[ii].i = sqlite3_value_int(aData[ii+3]);
+        cell.aCoord[ii+1].i = sqlite3_value_int(aData[ii+4]);
+        if( cell.aCoord[ii].i>cell.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(aData[2])!=SQLITE_NULL ){
+      cell.iRowid = sqlite3_value_int64(aData[2]);
+      if( sqlite3_value_type(aData[0])==SQLITE_NULL
+       || sqlite3_value_int64(aData[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 aData[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(aData[0])!=SQLITE_NULL ){
+    rc = rtreeDeleteRowid(pRtree, sqlite3_value_int64(aData[0]));
+  }
+
+  /* If the aData[] array contains more than one element, elements
+  ** (aData[2]..aData[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 = rtreeNewRowid(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;
+      }
+    }
+    if( pRtree->nAux ){
+      sqlite3_stmt *pUp = pRtree->pWriteAux;
+      int jj;
+      sqlite3_bind_int64(pUp, 1, *pRowid);
+      for(jj=0; jj<pRtree->nAux; jj++){
+        sqlite3_bind_value(pUp, jj+2, aData[pRtree->nDim2+3+jj]);
+      }
+      sqlite3_step(pUp);
+      rc = sqlite3_reset(pUp);
+    }
+  }
+
+constraint:
+  rtreeRelease(pRtree);
+  return rc;
+}
 
 /*
-** 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_<target name>" 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_<target> naming scheme. 
-**
-** Instead of the plain data_<target> naming scheme, RBU database tables 
-** may also be named data<integer>_<target>, where <integer> is any sequence
-** of zero or more numeric characters (0-9). This can be significant because
-** tables within the RBU database are always processed in order sorted by 
-** name. By judicious selection of the <integer> portion of the names
-** of the RBU tables the user can therefore control the order in which they
-** are processed. This can be useful, for example, to ensure that "external
-** content" FTS4 tables are updated before their underlying content tables.
-**
-** If the target database table is a virtual table or a table that has no
-** PRIMARY KEY declaration, the data_% table must also contain a column 
-** named "rbu_rowid". This column is mapped to the tables implicit primary 
-** key column - "rowid". Virtual tables for which the "rowid" column does 
-** not function like a primary key value cannot be updated using RBU. For 
-** 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:
+** 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.
 **
-**   CREATE TABLE data_ft1(a, b, langid, rbu_rowid, rbu_control);
-**   CREATE TABLE data_ft1(a, b, rbu_rowid, rbu_control);
+** 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:
 **
-** 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. 
+**   BEGIN;
+**     INSERT INTO rtree...
+**     DROP TABLE <tablename>;    -- Would fail with SQLITE_LOCKED
+**   COMMIT;
+*/
+static int rtreeSavepoint(sqlite3_vtab *pVtab, int iSavepoint){
+  Rtree *pRtree = (Rtree *)pVtab;
+  u8 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_str *p = sqlite3_str_new(db);
+    int ii;
+    sqlite3_str_appendf(p,
+       "CREATE TABLE \"%w\".\"%w_rowid\"(rowid INTEGER PRIMARY KEY,nodeno",
+       zDb, zPrefix);
+    for(ii=0; ii<pRtree->nAux; ii++){
+      sqlite3_str_appendf(p,",a%d",ii);
+    }
+    sqlite3_str_appendf(p,
+      ");CREATE TABLE \"%w\".\"%w_node\"(nodeno INTEGER PRIMARY KEY,data);",
+      zDb, zPrefix);
+    sqlite3_str_appendf(p,
+    "CREATE TABLE \"%w\".\"%w_parent\"(nodeno INTEGER PRIMARY KEY,parentnode);",
+      zDb, zPrefix);
+    sqlite3_str_appendf(p,
+       "INSERT INTO \"%w\".\"%w_node\"VALUES(1,zeroblob(%d))",
+       zDb, zPrefix, pRtree->iNodeSize);
+    zCreate = sqlite3_str_finish(p);
+    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; i<N_STATEMENT && rc==SQLITE_OK; i++){
+    char *zSql;
+    const char *zFormat;
+    if( i!=3 || pRtree->nAux==0 ){
+       zFormat = azSql[i];
+    }else {
+       /* An UPSERT is very slightly slower than REPLACE, but it is needed
+       ** if there are auxiliary columns */
+       zFormat = "INSERT INTO\"%w\".\"%w_rowid\"(rowid,nodeno)VALUES(?1,?2)"
+                  "ON CONFLICT(rowid)DO UPDATE SET nodeno=excluded.nodeno";
+    }
+    zSql = sqlite3_mprintf(zFormat, zDb, zPrefix);
+    if( zSql ){
+      rc = sqlite3_prepare_v3(db, zSql, -1, SQLITE_PREPARE_PERSISTENT,
+                              appStmt[i], 0); 
+    }else{
+      rc = SQLITE_NOMEM;
+    }
+    sqlite3_free(zSql);
+  }
+  if( pRtree->nAux ){
+    pRtree->zReadAuxSql = sqlite3_mprintf(
+       "SELECT * FROM \"%w\".\"%w_rowid\" WHERE rowid=?1",
+       zDb, zPrefix);
+    if( pRtree->zReadAuxSql==0 ){
+      rc = SQLITE_NOMEM;
+    }else{
+      sqlite3_str *p = sqlite3_str_new(db);
+      int ii;
+      char *zSql;
+      sqlite3_str_appendf(p, "UPDATE \"%w\".\"%w_rowid\"SET ", zDb, zPrefix);
+      for(ii=0; ii<pRtree->nAux; ii++){
+        if( ii ) sqlite3_str_append(p, ",", 1);
+        if( ii<pRtree->nAuxNotNull ){
+          sqlite3_str_appendf(p,"a%d=coalesce(?%d,a%d)",ii,ii+2,ii);
+        }else{
+          sqlite3_str_appendf(p,"a%d=?%d",ii,ii+2);
+        }
+      }
+      sqlite3_str_appendf(p, " WHERE rowid=?1");
+      zSql = sqlite3_str_finish(p);
+      if( zSql==0 ){
+        rc = SQLITE_NOMEM;
+      }else{
+        rc = sqlite3_prepare_v3(db, zSql, -1, SQLITE_PREPARE_PERSISTENT,
+                                &pRtree->pWriteAux, 0); 
+        sqlite3_free(zSql);
+      }
+    }
+  }
+
+  return rc;
+}
+
+/*
+** The second argument to this function contains the text of an SQL statement
+** that returns a single integer value. The statement is compiled and executed
+** using database connection db. If successful, the integer value returned
+** is written to *piVal and SQLITE_OK returned. Otherwise, an SQLite error
+** code is returned and the value of *piVal after returning is not defined.
+*/
+static int getIntFromStmt(sqlite3 *db, const char *zSql, int *piVal){
+  int rc = SQLITE_NOMEM;
+  if( zSql ){
+    sqlite3_stmt *pStmt = 0;
+    rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
+    if( rc==SQLITE_OK ){
+      if( SQLITE_ROW==sqlite3_step(pStmt) ){
+        *piVal = sqlite3_column_int(pStmt, 0);
+      }
+      rc = sqlite3_finalize(pStmt);
+    }
+  }
+  return rc;
+}
+
+/*
+** This function is called from within the xConnect() or xCreate() method to
+** determine the node-size used by the rtree table being created or connected
+** to. If successful, pRtree->iNodeSize is populated and SQLITE_OK returned.
+** Otherwise, an SQLite error code is returned.
 **
-** 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.
+** 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.
 **
-** 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.
+** 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)<pRtree->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));
+    }else if( pRtree->iNodeSize<(512-64) ){
+      rc = SQLITE_CORRUPT_VTAB;
+      *pzErr = sqlite3_mprintf("undersize RTree blobs in \"%q_node\"",
+                               pRtree->zName);
+    }
+  }
+
+  sqlite3_free(zSql);
+  return rc;
+}
+
+/* 
+** This function is the implementation of both the xConnect and xCreate
+** methods of the r-tree virtual table.
 **
-** 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:
+**   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);
+  sqlite3_str *pSql;
+  char *zSql;
+  int ii = 4;
+  int iErr;
+
+  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 */
+    "Auxiliary rtree columns must be last"                /* 4 */
+  };
+
+  assert( RTREE_MAX_AUX_COLUMN<256 ); /* Aux columns counted by a u8 */
+  if( argc>RTREE_MAX_AUX_COLUMN+3 ){
+    *pzErr = sqlite3_mprintf("%s", aErrMsg[3]);
+    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->eCoordType = (u8)eCoordType;
+  memcpy(pRtree->zDb, argv[1], nDb);
+  memcpy(pRtree->zName, argv[2], nName);
+
+
+  /* Create/Connect to the underlying relational database schema. If
+  ** that is successful, call sqlite3_declare_vtab() to configure
+  ** the r-tree table schema.
+  */
+  pSql = sqlite3_str_new(db);
+  sqlite3_str_appendf(pSql, "CREATE TABLE x(%s", argv[3]);
+  for(ii=4; ii<argc; ii++){
+    if( argv[ii][0]=='+' ){
+      pRtree->nAux++;
+      sqlite3_str_appendf(pSql, ",%s", argv[ii]+1);
+    }else if( pRtree->nAux>0 ){
+      break;
+    }else{
+      pRtree->nDim2++;
+      sqlite3_str_appendf(pSql, ",%s", argv[ii]);
+    }
+  }
+  sqlite3_str_appendf(pSql, ");");
+  zSql = sqlite3_str_finish(pSql);
+  if( !zSql ){
+    rc = SQLITE_NOMEM;
+  }else if( ii<argc ){
+    *pzErr = sqlite3_mprintf("%s", aErrMsg[4]);
+    rc = SQLITE_ERROR;
+  }else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){
+    *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+  }
+  sqlite3_free(zSql);
+  if( rc ) goto rtreeInit_fail;
+  pRtree->nDim = pRtree->nDim2/2;
+  if( pRtree->nDim<1 ){
+    iErr = 2;
+  }else if( pRtree->nDim2>RTREE_MAX_DIMENSIONS*2 ){
+    iErr = 3;
+  }else if( pRtree->nDim2 % 2 ){
+    iErr = 1;
+  }else{
+    iErr = 0;
+  }
+  if( iErr ){
+    *pzErr = sqlite3_mprintf("%s", aErrMsg[iErr]);
+    goto rtreeInit_fail;
+  }
+  pRtree->nBytesPerCell = 8 + pRtree->nDim2*4;
+
+  /* Figure out the node size to use. */
+  rc = getNodeSize(db, pRtree, isCreate, pzErr);
+  if( rc ) goto rtreeInit_fail;
+  rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate);
+  if( rc ){
+    *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+    goto rtreeInit_fail;
+  }
+
+  *ppVtab = (sqlite3_vtab *)pRtree;
+  return SQLITE_OK;
+
+rtreeInit_fail:
+  if( rc==SQLITE_OK ) rc = SQLITE_ERROR;
+  assert( *ppVtab==0 );
+  assert( pRtree->nBusy==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.
 **
-**   UPDATE t1 SET c = 'usa' WHERE a = 4;
+** 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:
 **
-** is represented by the data_t1 row created by:
+**   SELECT rtreenode(2, data) FROM rt_node;
 **
-**   INSERT INTO data_t1(a, b, c, rbu_control) VALUES(4, NULL, 'usa', '..x');
+** 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 
+** <num-dimension>*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; ii<NCELL(&node); ii++){
+    char zCell[512];
+    int nCell = 0;
+    RtreeCell cell;
+    int jj;
+
+    nodeGetCell(&tree, &node, ii, &cell);
+    sqlite3_snprintf(512-nCell,&zCell[nCell],"%lld", cell.iRowid);
+    nCell = (int)strlen(zCell);
+    for(jj=0; jj<tree.nDim2; jj++){
+#ifndef SQLITE_RTREE_INT_ONLY
+      sqlite3_snprintf(512-nCell,&zCell[nCell], " %g",
+                       (double)cell.aCoord[jj].f);
+#else
+      sqlite3_snprintf(512-nCell,&zCell[nCell], " %d",
+                       cell.aCoord[jj].i);
+#endif
+      nCell = (int)strlen(zCell);
+    }
+
+    if( zText ){
+      char *zTextNew = sqlite3_mprintf("%s {%s}", zText, zCell);
+      sqlite3_free(zText);
+      zText = zTextNew;
+    }else{
+      zText = sqlite3_mprintf("{%s}", zCell);
+    }
+  }
+  
+  sqlite3_result_text(ctx, zText, -1, sqlite3_free);
+}
+
+/* This routine implements an SQL function that returns the "depth" parameter
+** from the front of a blob that is an r-tree node.  For example:
 **
-** 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.
+**     SELECT rtreedepth(data) FROM rt_node WHERE nodeno=1;
 **
-** For example, this row:
+** The depth value is 0 for all nodes other than the root node, and the root
+** node always has nodeno=1, so the example above is the primary use for this
+** routine.  This routine is intended for testing and analysis only.
+*/
+static void rtreedepth(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
+  UNUSED_PARAMETER(nArg);
+  if( sqlite3_value_type(apArg[0])!=SQLITE_BLOB 
+   || sqlite3_value_bytes(apArg[0])<2
+  ){
+    sqlite3_result_error(ctx, "Invalid argument to rtreedepth()", -1); 
+  }else{
+    u8 *zBlob = (u8 *)sqlite3_value_blob(apArg[0]);
+    sqlite3_result_int(ctx, readInt16(zBlob));
+  }
+}
+
+/*
+** Context object passed between the various routines that make up the
+** implementation of integrity-check function rtreecheck().
+*/
+typedef struct RtreeCheck RtreeCheck;
+struct RtreeCheck {
+  sqlite3 *db;                    /* Database handle */
+  const char *zDb;                /* Database containing rtree table */
+  const char *zTab;               /* Name of rtree table */
+  int bInt;                       /* True for rtree_i32 table */
+  int nDim;                       /* Number of dimensions for this rtree tbl */
+  sqlite3_stmt *pGetNode;         /* Statement used to retrieve nodes */
+  sqlite3_stmt *aCheckMapping[2]; /* Statements to query %_parent/%_rowid */
+  int nLeaf;                      /* Number of leaf cells in table */
+  int nNonLeaf;                   /* Number of non-leaf cells in table */
+  int rc;                         /* Return code */
+  char *zReport;                  /* Message to report */
+  int nErr;                       /* Number of lines in zReport */
+};
+
+#define RTREE_CHECK_MAX_ERROR 100
+
+/*
+** Reset SQL statement pStmt. If the sqlite3_reset() call returns an error,
+** and RtreeCheck.rc==SQLITE_OK, set RtreeCheck.rc to the error code.
+*/
+static void rtreeCheckReset(RtreeCheck *pCheck, sqlite3_stmt *pStmt){
+  int rc = sqlite3_reset(pStmt);
+  if( pCheck->rc==SQLITE_OK ) pCheck->rc = rc;
+}
+
+/*
+** The second and subsequent arguments to this function are a format string
+** and printf style arguments. This function formats the string and attempts
+** to compile it as an SQL statement.
 **
-**   INSERT INTO data_t1(a, b, c, rbu_control) VALUES(4, NULL, 'usa', '..d');
+** If successful, a pointer to the new SQL statement is returned. Otherwise,
+** NULL is returned and an error code left in RtreeCheck.rc.
+*/
+static sqlite3_stmt *rtreeCheckPrepare(
+  RtreeCheck *pCheck,             /* RtreeCheck object */
+  const char *zFmt, ...           /* Format string and trailing args */
+){
+  va_list ap;
+  char *z;
+  sqlite3_stmt *pRet = 0;
+
+  va_start(ap, zFmt);
+  z = sqlite3_vmprintf(zFmt, ap);
+
+  if( pCheck->rc==SQLITE_OK ){
+    if( z==0 ){
+      pCheck->rc = SQLITE_NOMEM;
+    }else{
+      pCheck->rc = sqlite3_prepare_v2(pCheck->db, z, -1, &pRet, 0);
+    }
+  }
+
+  sqlite3_free(z);
+  va_end(ap);
+  return pRet;
+}
+
+/*
+** The second and subsequent arguments to this function are a printf()
+** style format string and arguments. This function formats the string and
+** appends it to the report being accumuated in pCheck.
+*/
+static void rtreeCheckAppendMsg(RtreeCheck *pCheck, const char *zFmt, ...){
+  va_list ap;
+  va_start(ap, zFmt);
+  if( pCheck->rc==SQLITE_OK && pCheck->nErr<RTREE_CHECK_MAX_ERROR ){
+    char *z = sqlite3_vmprintf(zFmt, ap);
+    if( z==0 ){
+      pCheck->rc = SQLITE_NOMEM;
+    }else{
+      pCheck->zReport = sqlite3_mprintf("%z%s%z", 
+          pCheck->zReport, (pCheck->zReport ? "\n" : ""), z
+      );
+      if( pCheck->zReport==0 ){
+        pCheck->rc = SQLITE_NOMEM;
+      }
+    }
+    pCheck->nErr++;
+  }
+  va_end(ap);
+}
+
+/*
+** This function is a no-op if there is already an error code stored
+** in the RtreeCheck object indicated by the first argument. NULL is
+** returned in this case.
 **
-** is similar to an UPDATE statement such as: 
+** Otherwise, the contents of rtree table node iNode are loaded from
+** the database and copied into a buffer obtained from sqlite3_malloc().
+** If no error occurs, a pointer to the buffer is returned and (*pnNode)
+** is set to the size of the buffer in bytes.
 **
-**   UPDATE t1 SET c = rbu_delta(c, 'usa') WHERE a = 4;
+** Or, if an error does occur, NULL is returned and an error code left
+** in the RtreeCheck object. The final value of *pnNode is undefined in
+** this case.
+*/
+static u8 *rtreeCheckGetNode(RtreeCheck *pCheck, i64 iNode, int *pnNode){
+  u8 *pRet = 0;                   /* Return value */
+
+  assert( pCheck->rc==SQLITE_OK );
+  if( pCheck->pGetNode==0 ){
+    pCheck->pGetNode = rtreeCheckPrepare(pCheck,
+        "SELECT data FROM %Q.'%q_node' WHERE nodeno=?", 
+        pCheck->zDb, pCheck->zTab
+    );
+  }
+
+  if( pCheck->rc==SQLITE_OK ){
+    sqlite3_bind_int64(pCheck->pGetNode, 1, iNode);
+    if( sqlite3_step(pCheck->pGetNode)==SQLITE_ROW ){
+      int nNode = sqlite3_column_bytes(pCheck->pGetNode, 0);
+      const u8 *pNode = (const u8*)sqlite3_column_blob(pCheck->pGetNode, 0);
+      pRet = sqlite3_malloc(nNode);
+      if( pRet==0 ){
+        pCheck->rc = SQLITE_NOMEM;
+      }else{
+        memcpy(pRet, pNode, nNode);
+        *pnNode = nNode;
+      }
+    }
+    rtreeCheckReset(pCheck, pCheck->pGetNode);
+    if( pCheck->rc==SQLITE_OK && pRet==0 ){
+      rtreeCheckAppendMsg(pCheck, "Node %lld missing from database", iNode);
+    }
+  }
+
+  return pRet;
+}
+
+/*
+** This function is used to check that the %_parent (if bLeaf==0) or %_rowid
+** (if bLeaf==1) table contains a specified entry. The schemas of the
+** two tables are:
 **
-** 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.
+**   CREATE TABLE %_parent(nodeno INTEGER PRIMARY KEY, parentnode INTEGER)
+**   CREATE TABLE %_rowid(rowid INTEGER PRIMARY KEY, nodeno INTEGER, ...)
 **
-** 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:
+** In both cases, this function checks that there exists an entry with
+** IPK value iKey and the second column set to iVal.
 **
-**   INSERT INTO data_ft1(a, b, rbu_rowid, rbu_control) 
-**       VALUES(NULL, 'usa', 12, '.x');
+*/
+static void rtreeCheckMapping(
+  RtreeCheck *pCheck,             /* RtreeCheck object */
+  int bLeaf,                      /* True for a leaf cell, false for interior */
+  i64 iKey,                       /* Key for mapping */
+  i64 iVal                        /* Expected value for mapping */
+){
+  int rc;
+  sqlite3_stmt *pStmt;
+  const char *azSql[2] = {
+    "SELECT parentnode FROM %Q.'%q_parent' WHERE nodeno=?1",
+    "SELECT nodeno FROM %Q.'%q_rowid' WHERE rowid=?1"
+  };
+
+  assert( bLeaf==0 || bLeaf==1 );
+  if( pCheck->aCheckMapping[bLeaf]==0 ){
+    pCheck->aCheckMapping[bLeaf] = rtreeCheckPrepare(pCheck,
+        azSql[bLeaf], pCheck->zDb, pCheck->zTab
+    );
+  }
+  if( pCheck->rc!=SQLITE_OK ) return;
+
+  pStmt = pCheck->aCheckMapping[bLeaf];
+  sqlite3_bind_int64(pStmt, 1, iKey);
+  rc = sqlite3_step(pStmt);
+  if( rc==SQLITE_DONE ){
+    rtreeCheckAppendMsg(pCheck, "Mapping (%lld -> %lld) missing from %s table",
+        iKey, iVal, (bLeaf ? "%_rowid" : "%_parent")
+    );
+  }else if( rc==SQLITE_ROW ){
+    i64 ii = sqlite3_column_int64(pStmt, 0);
+    if( ii!=iVal ){
+      rtreeCheckAppendMsg(pCheck, 
+          "Found (%lld -> %lld) in %s table, expected (%lld -> %lld)",
+          iKey, ii, (bLeaf ? "%_rowid" : "%_parent"), iKey, iVal
+      );
+    }
+  }
+  rtreeCheckReset(pCheck, pStmt);
+}
+
+/*
+** Argument pCell points to an array of coordinates stored on an rtree page.
+** This function checks that the coordinates are internally consistent (no
+** x1>x2 conditions) and adds an error message to the RtreeCheck object
+** if they are not.
 **
-** causes a result similar to:
+** Additionally, if pParent is not NULL, then it is assumed to point to
+** the array of coordinates on the parent page that bound the page 
+** containing pCell. In this case it is also verified that the two
+** sets of coordinates are mutually consistent and an error message added
+** to the RtreeCheck object if they are not.
+*/
+static void rtreeCheckCellCoord(
+  RtreeCheck *pCheck, 
+  i64 iNode,                      /* Node id to use in error messages */
+  int iCell,                      /* Cell number to use in error messages */
+  u8 *pCell,                      /* Pointer to cell coordinates */
+  u8 *pParent                     /* Pointer to parent coordinates */
+){
+  RtreeCoord c1, c2;
+  RtreeCoord p1, p2;
+  int i;
+
+  for(i=0; i<pCheck->nDim; i++){
+    readCoord(&pCell[4*2*i], &c1);
+    readCoord(&pCell[4*(2*i + 1)], &c2);
+
+    /* printf("%e, %e\n", c1.u.f, c2.u.f); */
+    if( pCheck->bInt ? c1.i>c2.i : c1.f>c2.f ){
+      rtreeCheckAppendMsg(pCheck, 
+          "Dimension %d of cell %d on node %lld is corrupt", i, iCell, iNode
+      );
+    }
+
+    if( pParent ){
+      readCoord(&pParent[4*2*i], &p1);
+      readCoord(&pParent[4*(2*i + 1)], &p2);
+
+      if( (pCheck->bInt ? c1.i<p1.i : c1.f<p1.f) 
+       || (pCheck->bInt ? c2.i>p2.i : c2.f>p2.f)
+      ){
+        rtreeCheckAppendMsg(pCheck, 
+            "Dimension %d of cell %d on node %lld is corrupt relative to parent"
+            , i, iCell, iNode
+        );
+      }
+    }
+  }
+}
+
+/*
+** Run rtreecheck() checks on node iNode, which is at depth iDepth within
+** the r-tree structure. Argument aParent points to the array of coordinates
+** that bound node iNode on the parent node.
 **
-**   UPDATE ft1 SET b = 'usa' WHERE rowid = 12;
+** If any problems are discovered, an error message is appended to the
+** report accumulated in the RtreeCheck object.
+*/
+static void rtreeCheckNode(
+  RtreeCheck *pCheck,
+  int iDepth,                     /* Depth of iNode (0==leaf) */
+  u8 *aParent,                    /* Buffer containing parent coords */
+  i64 iNode                       /* Node to check */
+){
+  u8 *aNode = 0;
+  int nNode = 0;
+
+  assert( iNode==1 || aParent!=0 );
+  assert( pCheck->nDim>0 );
+
+  aNode = rtreeCheckGetNode(pCheck, iNode, &nNode);
+  if( aNode ){
+    if( nNode<4 ){
+      rtreeCheckAppendMsg(pCheck, 
+          "Node %lld is too small (%d bytes)", iNode, nNode
+      );
+    }else{
+      int nCell;                  /* Number of cells on page */
+      int i;                      /* Used to iterate through cells */
+      if( aParent==0 ){
+        iDepth = readInt16(aNode);
+        if( iDepth>RTREE_MAX_DEPTH ){
+          rtreeCheckAppendMsg(pCheck, "Rtree depth out of range (%d)", iDepth);
+          sqlite3_free(aNode);
+          return;
+        }
+      }
+      nCell = readInt16(&aNode[2]);
+      if( (4 + nCell*(8 + pCheck->nDim*2*4))>nNode ){
+        rtreeCheckAppendMsg(pCheck, 
+            "Node %lld is too small for cell count of %d (%d bytes)", 
+            iNode, nCell, nNode
+        );
+      }else{
+        for(i=0; i<nCell; i++){
+          u8 *pCell = &aNode[4 + i*(8 + pCheck->nDim*2*4)];
+          i64 iVal = readInt64(pCell);
+          rtreeCheckCellCoord(pCheck, iNode, i, &pCell[8], aParent);
+
+          if( iDepth>0 ){
+            rtreeCheckMapping(pCheck, 0, iVal, iNode);
+            rtreeCheckNode(pCheck, iDepth-1, &pCell[8], iVal);
+            pCheck->nNonLeaf++;
+          }else{
+            rtreeCheckMapping(pCheck, 1, iVal, iNode);
+            pCheck->nLeaf++;
+          }
+        }
+      }
+    }
+    sqlite3_free(aNode);
+  }
+}
+
+/*
+** The second argument to this function must be either "_rowid" or
+** "_parent". This function checks that the number of entries in the
+** %_rowid or %_parent table is exactly nExpect. If not, it adds
+** an error message to the report in the RtreeCheck object indicated
+** by the first argument.
+*/
+static void rtreeCheckCount(RtreeCheck *pCheck, const char *zTbl, i64 nExpect){
+  if( pCheck->rc==SQLITE_OK ){
+    sqlite3_stmt *pCount;
+    pCount = rtreeCheckPrepare(pCheck, "SELECT count(*) FROM %Q.'%q%s'",
+        pCheck->zDb, pCheck->zTab, zTbl
+    );
+    if( pCount ){
+      if( sqlite3_step(pCount)==SQLITE_ROW ){
+        i64 nActual = sqlite3_column_int64(pCount, 0);
+        if( nActual!=nExpect ){
+          rtreeCheckAppendMsg(pCheck, "Wrong number of entries in %%%s table"
+              " - expected %lld, actual %lld" , zTbl, nExpect, nActual
+          );
+        }
+      }
+      pCheck->rc = sqlite3_finalize(pCount);
+    }
+  }
+}
+
+/*
+** This function does the bulk of the work for the rtree integrity-check.
+** It is called by rtreecheck(), which is the SQL function implementation.
+*/
+static int rtreeCheckTable(
+  sqlite3 *db,                    /* Database handle to access db through */
+  const char *zDb,                /* Name of db ("main", "temp" etc.) */
+  const char *zTab,               /* Name of rtree table to check */
+  char **pzReport                 /* OUT: sqlite3_malloc'd report text */
+){
+  RtreeCheck check;               /* Common context for various routines */
+  sqlite3_stmt *pStmt = 0;        /* Used to find column count of rtree table */
+  int bEnd = 0;                   /* True if transaction should be closed */
+  int nAux = 0;                   /* Number of extra columns. */
+
+  /* Initialize the context object */
+  memset(&check, 0, sizeof(check));
+  check.db = db;
+  check.zDb = zDb;
+  check.zTab = zTab;
+
+  /* If there is not already an open transaction, open one now. This is
+  ** to ensure that the queries run as part of this integrity-check operate
+  ** on a consistent snapshot.  */
+  if( sqlite3_get_autocommit(db) ){
+    check.rc = sqlite3_exec(db, "BEGIN", 0, 0, 0);
+    bEnd = 1;
+  }
+
+  /* Find the number of auxiliary columns */
+  if( check.rc==SQLITE_OK ){
+    pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab);
+    if( pStmt ){
+      nAux = sqlite3_column_count(pStmt) - 2;
+      sqlite3_finalize(pStmt);
+    }
+    check.rc = SQLITE_OK;
+  }
+
+  /* Find number of dimensions in the rtree table. */
+  pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.%Q", zDb, zTab);
+  if( pStmt ){
+    int rc;
+    check.nDim = (sqlite3_column_count(pStmt) - 1 - nAux) / 2;
+    if( check.nDim<1 ){
+      rtreeCheckAppendMsg(&check, "Schema corrupt or not an rtree");
+    }else if( SQLITE_ROW==sqlite3_step(pStmt) ){
+      check.bInt = (sqlite3_column_type(pStmt, 1)==SQLITE_INTEGER);
+    }
+    rc = sqlite3_finalize(pStmt);
+    if( rc!=SQLITE_CORRUPT ) check.rc = rc;
+  }
+
+  /* Do the actual integrity-check */
+  if( check.nDim>=1 ){
+    if( check.rc==SQLITE_OK ){
+      rtreeCheckNode(&check, 0, 0, 1);
+    }
+    rtreeCheckCount(&check, "_rowid", check.nLeaf);
+    rtreeCheckCount(&check, "_parent", check.nNonLeaf);
+  }
+
+  /* Finalize SQL statements used by the integrity-check */
+  sqlite3_finalize(check.pGetNode);
+  sqlite3_finalize(check.aCheckMapping[0]);
+  sqlite3_finalize(check.aCheckMapping[1]);
+
+  /* If one was opened, close the transaction */
+  if( bEnd ){
+    int rc = sqlite3_exec(db, "END", 0, 0, 0);
+    if( check.rc==SQLITE_OK ) check.rc = rc;
+  }
+  *pzReport = check.zReport;
+  return check.rc;
+}
+
+/*
+** Usage:
 **
-** 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.
+**   rtreecheck(<rtree-table>);
+**   rtreecheck(<database>, <rtree-table>);
 **
-** USAGE
+** Invoking this SQL function runs an integrity-check on the named rtree
+** table. The integrity-check verifies the following:
 **
-** The API declared below allows an application to apply an RBU update 
-** stored on disk to an existing target database. Essentially, the 
-** application:
+**   1. For each cell in the r-tree structure (%_node table), that:
 **
-**     1) Opens an RBU handle using the sqlite3rbu_open() function.
+**       a) for each dimension, (coord1 <= coord2).
 **
-**     2) Registers any required virtual table modules with the database
-**        handle returned by sqlite3rbu_db(). Also, if required, register
-**        the rbu_delta() implementation.
+**       b) unless the cell is on the root node, that the cell is bounded
+**          by the parent cell on the parent node.
 **
-**     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.
+**       c) for leaf nodes, that there is an entry in the %_rowid 
+**          table corresponding to the cell's rowid value that 
+**          points to the correct node.
 **
-**     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.
+**       d) for cells on non-leaf nodes, that there is an entry in the 
+**          %_parent table mapping from the cell's child node to the
+**          node that it resides on.
 **
-** See comments below for more detail on APIs.
+**   2. That there are the same number of entries in the %_rowid table
+**      as there are leaf cells in the r-tree structure, and that there
+**      is a leaf cell that corresponds to each entry in the %_rowid table.
 **
-** 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.
+**   3. That there are the same number of entries in the %_parent table
+**      as there are non-leaf cells in the r-tree structure, and that 
+**      there is a non-leaf cell that corresponds to each entry in the 
+**      %_parent table.
+*/
+static void rtreecheck(
+  sqlite3_context *ctx, 
+  int nArg, 
+  sqlite3_value **apArg
+){
+  if( nArg!=1 && nArg!=2 ){
+    sqlite3_result_error(ctx, 
+        "wrong number of arguments to function rtreecheck()", -1
+    );
+  }else{
+    int rc;
+    char *zReport = 0;
+    const char *zDb = (const char*)sqlite3_value_text(apArg[0]);
+    const char *zTab;
+    if( nArg==1 ){
+      zTab = zDb;
+      zDb = "main";
+    }else{
+      zTab = (const char*)sqlite3_value_text(apArg[1]);
+    }
+    rc = rtreeCheckTable(sqlite3_context_db_handle(ctx), zDb, zTab, &zReport);
+    if( rc==SQLITE_OK ){
+      sqlite3_result_text(ctx, zReport ? zReport : "ok", -1, SQLITE_TRANSIENT);
+    }else{
+      sqlite3_result_error_code(ctx, rc);
+    }
+    sqlite3_free(zReport);
+  }
+}
+
+/* Conditionally include the geopoly code */
+#ifdef SQLITE_ENABLE_GEOPOLY
+/************** Include geopoly.c in the middle of rtree.c *******************/
+/************** Begin file geopoly.c *****************************************/
+/*
+** 2018-05-25
 **
-** 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_"
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
 **
-** DATABASE LOCKING
+**    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 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.
+** This file implements an alternative R-Tree virtual table that
+** uses polygons to express the boundaries of 2-dimensional objects.
 **
-** 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).
+** This file is #include-ed onto the end of "rtree.c" so that it has
+** access to all of the R-Tree internals.
 */
+/* #include <stdlib.h> */
 
-#ifndef _SQLITE3RBU_H
-#define _SQLITE3RBU_H
-
-/* #include "sqlite3.h"              ** Required for error code definitions ** */
-
-#if 0
-extern "C" {
+/* Enable -DGEOPOLY_ENABLE_DEBUG for debugging facilities */
+#ifdef GEOPOLY_ENABLE_DEBUG
+  static int geo_debug = 0;
+# define GEODEBUG(X) if(geo_debug)printf X
+#else
+# define GEODEBUG(X)
 #endif
 
-typedef struct sqlite3rbu sqlite3rbu;
-
+#ifndef JSON_NULL   /* The following stuff repeats things found in json1 */
 /*
-** 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.
+** Versions of isspace(), isalnum() and isdigit() to which it is safe
+** to pass signed char values.
 */
-SQLITE_API sqlite3rbu *sqlite3rbu_open(
-  const char *zTarget, 
-  const char *zRbu,
-  const char *zState
-);
+#ifdef sqlite3Isdigit
+   /* Use the SQLite core versions if this routine is part of the
+   ** SQLite amalgamation */
+#  define safe_isdigit(x)  sqlite3Isdigit(x)
+#  define safe_isalnum(x)  sqlite3Isalnum(x)
+#  define safe_isxdigit(x) sqlite3Isxdigit(x)
+#else
+   /* Use the standard library for separate compilation */
+#include <ctype.h>  /* amalgamator: keep */
+#  define safe_isdigit(x)  isdigit((unsigned char)(x))
+#  define safe_isalnum(x)  isalnum((unsigned char)(x))
+#  define safe_isxdigit(x) isxdigit((unsigned char)(x))
+#endif
 
 /*
-** 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 "<database>-vacuum", where <database>
-** is the name of the target database file. In this case, on UNIX, if the
-** state database is not already present in the file-system, it is created
-** with the same permissions as the target db is made.
-**
-** 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.
+** Growing our own isspace() routine this way is twice as fast as
+** the library isspace() function.
+*/
+static const char geopolyIsSpace[] = {
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 1, 1, 0, 0, 1, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  1, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
+};
+#define safe_isspace(x) (geopolyIsSpace[(unsigned char)x])
+#endif /* JSON NULL - back to original code */
+
+/* Compiler and version */
+#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
+#ifndef MSVC_VERSION
+#if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC)
+# define MSVC_VERSION _MSC_VER
+#else
+# define MSVC_VERSION 0
+#endif
+#endif
+
+/* Datatype for coordinates
 */
-SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
-  const char *zTarget, 
-  const char *zState
-);
+typedef float GeoCoord;
 
 /*
-** Configure a limit for the amount of temp space that may be used by
-** the RBU handle passed as the first argument. The new limit is specified
-** in bytes by the second parameter. If it is positive, the limit is updated.
-** If the second parameter to this function is passed zero, then the limit
-** is removed entirely. If the second parameter is negative, the limit is
-** not modified (this is useful for querying the current limit).
+** Internal representation of a polygon.
 **
-** In all cases the returned value is the current limit in bytes (zero 
-** indicates unlimited).
+** The polygon consists of a sequence of vertexes.  There is a line
+** segment between each pair of vertexes, and one final segment from
+** the last vertex back to the first.  (This differs from the GeoJSON
+** standard in which the final vertex is a repeat of the first.)
 **
-** If the temp space limit is exceeded during operation, an SQLITE_FULL
-** error is returned.
+** The polygon follows the right-hand rule.  The area to the right of
+** each segment is "outside" and the area to the left is "inside".
+**
+** The on-disk representation consists of a 4-byte header followed by
+** the values.  The 4-byte header is:
+**
+**      encoding    (1 byte)   0=big-endian, 1=little-endian
+**      nvertex     (3 bytes)  Number of vertexes as a big-endian integer
 */
-SQLITE_API sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu*, sqlite3_int64);
+typedef struct GeoPoly GeoPoly;
+struct GeoPoly {
+  int nVertex;          /* Number of vertexes */
+  unsigned char hdr[4]; /* Header for on-disk representation */
+  GeoCoord a[2];    /* 2*nVertex values. X (longitude) first, then Y */
+};
 
 /*
-** Return the current amount of temp file space, in bytes, currently used by 
-** the RBU handle passed as the only argument.
+** State of a parse of a GeoJSON input.
 */
-SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu*);
+typedef struct GeoParse GeoParse;
+struct GeoParse {
+  const unsigned char *z;   /* Unparsed input */
+  int nVertex;              /* Number of vertexes in a[] */
+  int nAlloc;               /* Space allocated to a[] */
+  int nErr;                 /* Number of errors encountered */
+  GeoCoord *a;          /* Array of vertexes.  From sqlite3_malloc64() */
+};
+
+/* Do a 4-byte byte swap */
+static void geopolySwab32(unsigned char *a){
+  unsigned char t = a[0];
+  a[0] = a[3];
+  a[3] = t;
+  t = a[1];
+  a[1] = a[2];
+  a[2] = t;
+}
+
+/* Skip whitespace.  Return the next non-whitespace character. */
+static char geopolySkipSpace(GeoParse *p){
+  while( p->z[0] && safe_isspace(p->z[0]) ) p->z++;
+  return p->z[0];
+}
+
+/* Parse out a number.  Write the value into *pVal if pVal!=0.
+** return non-zero on success and zero if the next token is not a number.
+*/
+static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){
+  char c = geopolySkipSpace(p);
+  const unsigned char *z = p->z;
+  int j = 0;
+  int seenDP = 0;
+  int seenE = 0;
+  if( c=='-' ){
+    j = 1;
+    c = z[j];
+  }
+  if( c=='0' && z[j+1]>='0' && z[j+1]<='9' ) return 0;
+  for(;; j++){
+    c = z[j];
+    if( c>='0' && c<='9' ) continue;
+    if( c=='.' ){
+      if( z[j-1]=='-' ) return 0;
+      if( seenDP ) return 0;
+      seenDP = 1;
+      continue;
+    }
+    if( c=='e' || c=='E' ){
+      if( z[j-1]<'0' ) return 0;
+      if( seenE ) return -1;
+      seenDP = seenE = 1;
+      c = z[j+1];
+      if( c=='+' || c=='-' ){
+        j++;
+        c = z[j+1];
+      }
+      if( c<'0' || c>'9' ) return 0;
+      continue;
+    }
+    break;
+  }
+  if( z[j-1]<'0' ) return 0;
+  if( pVal ) *pVal = (GeoCoord)atof((const char*)p->z);
+  p->z += j;
+  return 1;
+}
 
 /*
-** 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.
+** If the input is a well-formed JSON array of coordinates with at least
+** four coordinates and where each coordinate is itself a two-value array,
+** then convert the JSON into a GeoPoly object and return a pointer to
+** that object.
 **
-** Database handles returned by this function remain valid until the next
-** call to any sqlite3rbu_xxx() function other than sqlite3rbu_db().
+** If any error occurs, return NULL.
 */
-SQLITE_API sqlite3 *sqlite3rbu_db(sqlite3rbu*, int bRbu);
+static GeoPoly *geopolyParseJson(const unsigned char *z, int *pRc){
+  GeoParse s;
+  int rc = SQLITE_OK;
+  memset(&s, 0, sizeof(s));
+  s.z = z;
+  if( geopolySkipSpace(&s)=='[' ){
+    s.z++;
+    while( geopolySkipSpace(&s)=='[' ){
+      int ii = 0;
+      char c;
+      s.z++;
+      if( s.nVertex>=s.nAlloc ){
+        GeoCoord *aNew;
+        s.nAlloc = s.nAlloc*2 + 16;
+        aNew = sqlite3_realloc64(s.a, s.nAlloc*sizeof(GeoCoord)*2 );
+        if( aNew==0 ){
+          rc = SQLITE_NOMEM;
+          s.nErr++;
+          break;
+        }
+        s.a = aNew;
+      }
+      while( geopolyParseNumber(&s, ii<=1 ? &s.a[s.nVertex*2+ii] : 0) ){
+        ii++;
+        if( ii==2 ) s.nVertex++;
+        c = geopolySkipSpace(&s);
+        s.z++;
+        if( c==',' ) continue;
+        if( c==']' && ii>=2 ) break;
+        s.nErr++;
+        rc = SQLITE_ERROR;
+        goto parse_json_err;
+      }
+      if( geopolySkipSpace(&s)==',' ){
+        s.z++;
+        continue;
+      }
+      break;
+    }
+    if( geopolySkipSpace(&s)==']'
+     && s.nVertex>=4
+     && s.a[0]==s.a[s.nVertex*2-2]
+     && s.a[1]==s.a[s.nVertex*2-1]
+     && (s.z++, geopolySkipSpace(&s)==0)
+    ){
+      int nByte;
+      GeoPoly *pOut;
+      int x = 1;
+      s.nVertex--;  /* Remove the redundant vertex at the end */
+      nByte = sizeof(GeoPoly) * s.nVertex*2*sizeof(GeoCoord);
+      pOut = sqlite3_malloc64( nByte );
+      x = 1;
+      if( pOut==0 ) goto parse_json_err;
+      pOut->nVertex = s.nVertex;
+      memcpy(pOut->a, s.a, s.nVertex*2*sizeof(GeoCoord));
+      pOut->hdr[0] = *(unsigned char*)&x;
+      pOut->hdr[1] = (s.nVertex>>16)&0xff;
+      pOut->hdr[2] = (s.nVertex>>8)&0xff;
+      pOut->hdr[3] = s.nVertex&0xff;
+      sqlite3_free(s.a);
+      if( pRc ) *pRc = SQLITE_OK;
+      return pOut;
+    }else{
+      s.nErr++;
+      rc = SQLITE_ERROR;
+    }
+  }
+parse_json_err:
+  if( pRc ) *pRc = rc;
+  sqlite3_free(s.a);
+  return 0;
+}
 
 /*
-** 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.
+** Given a function parameter, try to interpret it as a polygon, either
+** in the binary format or JSON text.  Compute a GeoPoly object and
+** return a pointer to that object.  Or if the input is not a well-formed
+** polygon, put an error message in sqlite3_context and return NULL.
 */
-SQLITE_API int sqlite3rbu_step(sqlite3rbu *pRbu);
+static GeoPoly *geopolyFuncParam(
+  sqlite3_context *pCtx,      /* Context for error messages */
+  sqlite3_value *pVal,        /* The value to decode */
+  int *pRc                    /* Write error here */
+){
+  GeoPoly *p = 0;
+  int nByte;
+  if( sqlite3_value_type(pVal)==SQLITE_BLOB
+   && (nByte = sqlite3_value_bytes(pVal))>=(4+6*sizeof(GeoCoord))
+  ){
+    const unsigned char *a = sqlite3_value_blob(pVal);
+    int nVertex;
+    nVertex = (a[1]<<16) + (a[2]<<8) + a[3];
+    if( (a[0]==0 || a[0]==1)
+     && (nVertex*2*sizeof(GeoCoord) + 4)==(unsigned int)nByte
+    ){
+      p = sqlite3_malloc64( sizeof(*p) + (nVertex-1)*2*sizeof(GeoCoord) );
+      if( p==0 ){
+        if( pRc ) *pRc = SQLITE_NOMEM;
+        if( pCtx ) sqlite3_result_error_nomem(pCtx);
+      }else{
+        int x = 1;
+        p->nVertex = nVertex;
+        memcpy(p->hdr, a, nByte);
+        if( a[0] != *(unsigned char*)&x ){
+          int ii;
+          for(ii=0; ii<nVertex*2; ii++){
+            geopolySwab32((unsigned char*)&p->a[ii]);
+          }
+          p->hdr[0] ^= 1;
+        }
+      }
+    }
+    if( pRc ) *pRc = SQLITE_OK;
+    return p;
+  }else if( sqlite3_value_type(pVal)==SQLITE_TEXT ){
+    const unsigned char *zJson = sqlite3_value_text(pVal);
+    if( zJson==0 ){
+      if( pRc ) *pRc = SQLITE_NOMEM;
+      return 0;
+    }
+    return geopolyParseJson(zJson, pRc);
+  }else{
+    if( pRc ) *pRc = SQLITE_ERROR;
+    return 0;
+  }
+}
 
 /*
-** Force RBU to save its state to disk.
+** Implementation of the geopoly_blob(X) function.
 **
-** 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.
+** If the input is a well-formed Geopoly BLOB or JSON string
+** then return the BLOB representation of the polygon.  Otherwise
+** return NULL.
 */
-SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu);
+static void geopolyBlobFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
+  if( p ){
+    sqlite3_result_blob(context, p->hdr, 
+       4+8*p->nVertex, SQLITE_TRANSIENT);
+    sqlite3_free(p);
+  }
+}
 
 /*
-** 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, if pzErrmsg is not NULL,
-** *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().
+** SQL function:     geopoly_json(X)
 **
-** 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.
+** Interpret X as a polygon and render it as a JSON array
+** of coordinates.  Or, if X is not a valid polygon, return NULL.
 */
-SQLITE_API int sqlite3rbu_close(sqlite3rbu *pRbu, char **pzErrmsg);
+static void geopolyJsonFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
+  if( p ){
+    sqlite3 *db = sqlite3_context_db_handle(context);
+    sqlite3_str *x = sqlite3_str_new(db);
+    int i;
+    sqlite3_str_append(x, "[", 1);
+    for(i=0; i<p->nVertex; i++){
+      sqlite3_str_appendf(x, "[%!g,%!g],", p->a[i*2], p->a[i*2+1]);
+    }
+    sqlite3_str_appendf(x, "[%!g,%!g]]", p->a[0], p->a[1]);
+    sqlite3_result_text(context, sqlite3_str_finish(x), -1, sqlite3_free);
+    sqlite3_free(p);
+  }
+}
 
 /*
-** 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.
+** SQL function:     geopoly_svg(X, ....)
+**
+** Interpret X as a polygon and render it as a SVG <polyline>.
+** Additional arguments are added as attributes to the <polyline>.
 */
-SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu);
+static void geopolySvgFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
+  if( p ){
+    sqlite3 *db = sqlite3_context_db_handle(context);
+    sqlite3_str *x = sqlite3_str_new(db);
+    int i;
+    char cSep = '\'';
+    sqlite3_str_appendf(x, "<polyline points=");
+    for(i=0; i<p->nVertex; i++){
+      sqlite3_str_appendf(x, "%c%g,%g", cSep, p->a[i*2], p->a[i*2+1]);
+      cSep = ' ';
+    }
+    sqlite3_str_appendf(x, " %g,%g'", p->a[0], p->a[1]);
+    for(i=1; i<argc; i++){
+      const char *z = (const char*)sqlite3_value_text(argv[i]);
+      if( z && z[0] ){
+        sqlite3_str_appendf(x, " %s", z);
+      }
+    }
+    sqlite3_str_appendf(x, "></polyline>");
+    sqlite3_result_text(context, sqlite3_str_finish(x), -1, sqlite3_free);
+    sqlite3_free(p);
+  }
+}
 
 /*
-** 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.
+** SQL Function:      geopoly_xform(poly, A, B, C, D, E, F)
 **
-** 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.
+** Transform and/or translate a polygon as follows:
 **
-** 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.
+**      x1 = A*x0 + B*y0 + E
+**      y1 = C*x0 + D*y0 + F
 **
-** 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:
+** For a translation:
 **
-**   CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID;
+**      geopoly_xform(poly, 1, 0, 0, 1, x-offset, y-offset)
 **
-** 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.
+** Rotate by R around the point (0,0):
 **
-** 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.
+**      geopoly_xform(poly, cos(R), sin(R), -sin(R), cos(R), 0, 0)
 */
-SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int*pnTwo);
+static void geopolyXformFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
+  double A = sqlite3_value_double(argv[1]);
+  double B = sqlite3_value_double(argv[2]);
+  double C = sqlite3_value_double(argv[3]);
+  double D = sqlite3_value_double(argv[4]);
+  double E = sqlite3_value_double(argv[5]);
+  double F = sqlite3_value_double(argv[6]);
+  GeoCoord x1, y1, x0, y0;
+  int ii;
+  if( p ){
+    for(ii=0; ii<p->nVertex; ii++){
+      x0 = p->a[ii*2];
+      y0 = p->a[ii*2+1];
+      x1 = (GeoCoord)(A*x0 + B*y0 + E);
+      y1 = (GeoCoord)(C*x0 + D*y0 + F);
+      p->a[ii*2] = x1;
+      p->a[ii*2+1] = y1;
+    }
+    sqlite3_result_blob(context, p->hdr, 
+       4+8*p->nVertex, SQLITE_TRANSIENT);
+    sqlite3_free(p);
+  }
+}
 
 /*
-** 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.
+** Implementation of the geopoly_area(X) function.
 **
-** 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.
+** If the input is a well-formed Geopoly BLOB then return the area
+** enclosed by the polygon.  If the polygon circulates clockwise instead
+** of counterclockwise (as it should) then return the negative of the
+** enclosed area.  Otherwise return NULL.
 */
-#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);
+static void geopolyAreaFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
+  if( p ){
+    double rArea = 0.0;
+    int ii;
+    for(ii=0; ii<p->nVertex-1; ii++){
+      rArea += (p->a[ii*2] - p->a[ii*2+2])           /* (x0 - x1) */
+                * (p->a[ii*2+1] + p->a[ii*2+3])      /* (y0 + y1) */
+                * 0.5;
+    }
+    rArea += (p->a[ii*2] - p->a[0])                  /* (xN - x0) */
+             * (p->a[ii*2+1] + p->a[1])              /* (yN + y0) */
+             * 0.5;
+    sqlite3_result_double(context, rArea);
+    sqlite3_free(p);
+  }            
+}
 
 /*
-** 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);
+** If pPoly is a polygon, compute its bounding box. Then:
 **
-** 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.
+**    (1) if aCoord!=0 store the bounding box in aCoord, returning NULL
+**    (2) otherwise, compute a GeoPoly for the bounding box and return the
+**        new GeoPoly
 **
-** 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.
+** If pPoly is NULL but aCoord is not NULL, then compute a new GeoPoly from
+** the bounding box in aCoord and return a pointer to that GeoPoly.
 */
-SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent);
+static GeoPoly *geopolyBBox(
+  sqlite3_context *context,   /* For recording the error */
+  sqlite3_value *pPoly,       /* The polygon */
+  RtreeCoord *aCoord,         /* Results here */
+  int *pRc                    /* Error code here */
+){
+  GeoPoly *pOut = 0;
+  GeoPoly *p;
+  float mnX, mxX, mnY, mxY;
+  if( pPoly==0 && aCoord!=0 ){
+    p = 0;
+    mnX = aCoord[0].f;
+    mxX = aCoord[1].f;
+    mnY = aCoord[2].f;
+    mxY = aCoord[3].f;
+    goto geopolyBboxFill;
+  }else{
+    p = geopolyFuncParam(context, pPoly, pRc);
+  }
+  if( p ){
+    int ii;
+    mnX = mxX = p->a[0];
+    mnY = mxY = p->a[1];
+    for(ii=1; ii<p->nVertex; ii++){
+      double r = p->a[ii*2];
+      if( r<mnX ) mnX = (float)r;
+      else if( r>mxX ) mxX = (float)r;
+      r = p->a[ii*2+1];
+      if( r<mnY ) mnY = (float)r;
+      else if( r>mxY ) mxY = (float)r;
+    }
+    if( pRc ) *pRc = SQLITE_OK;
+    if( aCoord==0 ){
+      geopolyBboxFill:
+      pOut = sqlite3_realloc(p, sizeof(GeoPoly)+sizeof(GeoCoord)*6);
+      if( pOut==0 ){
+        sqlite3_free(p);
+        if( context ) sqlite3_result_error_nomem(context);
+        if( pRc ) *pRc = SQLITE_NOMEM;
+        return 0;
+      }
+      pOut->nVertex = 4;
+      ii = 1;
+      pOut->hdr[0] = *(unsigned char*)&ii;
+      pOut->hdr[1] = 0;
+      pOut->hdr[2] = 0;
+      pOut->hdr[3] = 4;
+      pOut->a[0] = mnX;
+      pOut->a[1] = mnY;
+      pOut->a[2] = mxX;
+      pOut->a[3] = mnY;
+      pOut->a[4] = mxX;
+      pOut->a[5] = mxY;
+      pOut->a[6] = mnX;
+      pOut->a[7] = mxY;
+    }else{
+      sqlite3_free(p);
+      aCoord[0].f = mnX;
+      aCoord[1].f = mxX;
+      aCoord[2].f = mnY;
+      aCoord[3].f = mxY;
+    }
+  }
+  return pOut;
+}
 
 /*
-** 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.
+** Implementation of the geopoly_bbox(X) SQL function.
 */
-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
+static void geopolyBBoxFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  GeoPoly *p = geopolyBBox(context, argv[0], 0, 0);
+  if( p ){
+    sqlite3_result_blob(context, p->hdr, 
+       4+8*p->nVertex, SQLITE_TRANSIENT);
+    sqlite3_free(p);
+  }
+}
 
-/* Delta checksums disabled by default.  Compile with -DRBU_ENABLE_DELTA_CKSUM
-** to enable checksum verification.
+/*
+** State vector for the geopoly_group_bbox() aggregate function.
 */
-#ifndef RBU_ENABLE_DELTA_CKSUM
-# define RBU_ENABLE_DELTA_CKSUM 0
-#endif
+typedef struct GeoBBox GeoBBox;
+struct GeoBBox {
+  int isInit;
+  RtreeCoord a[4];
+};
+
 
 /*
-** Swap two objects of type TYPE.
+** Implementation of the geopoly_group_bbox(X) aggregate SQL function.
 */
-#if !defined(SQLITE_AMALGAMATION)
-# define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;}
-#endif
+static void geopolyBBoxStep(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  RtreeCoord a[4];
+  int rc = SQLITE_OK;
+  (void)geopolyBBox(context, argv[0], a, &rc);
+  if( rc==SQLITE_OK ){
+    GeoBBox *pBBox;
+    pBBox = (GeoBBox*)sqlite3_aggregate_context(context, sizeof(*pBBox));
+    if( pBBox==0 ) return;
+    if( pBBox->isInit==0 ){
+      pBBox->isInit = 1;
+      memcpy(pBBox->a, a, sizeof(RtreeCoord)*4);
+    }else{
+      if( a[0].f < pBBox->a[0].f ) pBBox->a[0] = a[0];
+      if( a[1].f > pBBox->a[1].f ) pBBox->a[1] = a[1];
+      if( a[2].f < pBBox->a[2].f ) pBBox->a[2] = a[2];
+      if( a[3].f > pBBox->a[3].f ) pBBox->a[3] = a[3];
+    }
+  }
+}
+static void geopolyBBoxFinal(
+  sqlite3_context *context
+){
+  GeoPoly *p;
+  GeoBBox *pBBox;
+  pBBox = (GeoBBox*)sqlite3_aggregate_context(context, 0);
+  if( pBBox==0 ) return;
+  p = geopolyBBox(context, 0, pBBox->a, 0);
+  if( p ){
+    sqlite3_result_blob(context, p->hdr, 
+       4+8*p->nVertex, SQLITE_TRANSIENT);
+    sqlite3_free(p);
+  }
+}
+
 
 /*
-** 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.
+** Determine if point (x0,y0) is beneath line segment (x1,y1)->(x2,y2).
+** Returns:
 **
-** 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).
+**    +2  x0,y0 is on the line segement
 **
-** RBU_STATE_COOKIE:
-**   Valid if STAGE==1. The current change-counter cookie value in the 
-**   target db file.
+**    +1  x0,y0 is beneath line segment
 **
-** RBU_STATE_OALSZ:
-**   Valid if STAGE==1. The size in bytes of the *-oal file.
+**    0   x0,y0 is not on or beneath the line segment or the line segment
+**        is vertical and x0,y0 is not on the line segment
 **
-** RBU_STATE_DATATBL:
-**   Only valid if STAGE==1. The RBU database name of the table 
-**   currently being read.
-*/
-#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_STATE_DATATBL     10
-
-#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.
+** The left-most coordinate min(x1,x2) is not considered to be part of
+** the line segment for the purposes of this analysis.
 */
-#define WAL_LOCK_WRITE  0
-#define WAL_LOCK_CKPT   1
-#define WAL_LOCK_READ0  3
-
-#define SQLITE_FCNTL_RBUCNT    5149216
+static int pointBeneathLine(
+  double x0, double y0,
+  double x1, double y1,
+  double x2, double y2
+){
+  double y;
+  if( x0==x1 && y0==y1 ) return 2;
+  if( x1<x2 ){
+    if( x0<=x1 || x0>x2 ) return 0;
+  }else if( x1>x2 ){
+    if( x0<=x2 || x0>x1 ) return 0;
+  }else{
+    /* Vertical line segment */
+    if( x0!=x1 ) return 0;
+    if( y0<y1 && y0<y2 ) return 0;
+    if( y0>y1 && y0>y2 ) return 0;
+    return 2;
+  }
+  y = y1 + (y2-y1)*(x0-x1)/(x2-x1);
+  if( y0==y ) return 2;
+  if( y0<y ) return 1;
+  return 0;
+}
 
 /*
-** A structure to store values read from the rbu_state table in memory.
+** SQL function:    geopoly_contains_point(P,X,Y)
+**
+** Return +2 if point X,Y is within polygon P.
+** Return +1 if point X,Y is on the polygon boundary.
+** Return 0 if point X,Y is outside the polygon
 */
-struct RbuState {
-  int eStage;
-  char *zTbl;
-  char *zDataTbl;
-  char *zIdx;
-  i64 iWalCksum;
-  int nRow;
-  i64 nProgress;
-  u32 iCookie;
-  i64 iOalSz;
-  i64 nPhaseOneStep;
-};
+static void geopolyContainsPointFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0);
+  double x0 = sqlite3_value_double(argv[1]);
+  double y0 = sqlite3_value_double(argv[2]);
+  int v = 0;
+  int cnt = 0;
+  int ii;
+  if( p1==0 ) return;
+  for(ii=0; ii<p1->nVertex-1; ii++){
+    v = pointBeneathLine(x0,y0,p1->a[ii*2],p1->a[ii*2+1],
+                               p1->a[ii*2+2],p1->a[ii*2+3]);
+    if( v==2 ) break;
+    cnt += v;
+  }
+  if( v!=2 ){
+    v = pointBeneathLine(x0,y0,p1->a[ii*2],p1->a[ii*2+1],
+                               p1->a[0],p1->a[1]);
+  }
+  if( v==2 ){
+    sqlite3_result_int(context, 1);
+  }else if( ((v+cnt)&1)==0 ){
+    sqlite3_result_int(context, 0);
+  }else{
+    sqlite3_result_int(context, 2);
+  }
+  sqlite3_free(p1);
+}
 
-struct RbuUpdateStmt {
-  char *zMask;                    /* Copy of update mask used with pUpdate */
-  sqlite3_stmt *pUpdate;          /* Last update statement (or NULL) */
-  RbuUpdateStmt *pNext;
-};
+/* Forward declaration */
+static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2);
 
 /*
-** 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:
+** SQL function:    geopoly_within(P1,P2)
 **
-**     * the table itself, 
-**     * each index of the table (zero or more points to visit), and
-**     * a special "cleanup table" state.
+** Return +2 if P1 and P2 are the same polygon
+** Return +1 if P2 is contained within P1
+** Return 0 if any part of P2 is on the outside of P1
 **
-** 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 */
+static void geopolyWithinFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0);
+  GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0);
+  if( p1 && p2 ){
+    int x = geopolyOverlap(p1, p2);
+    if( x<0 ){
+      sqlite3_result_error_nomem(context);
+    }else{
+      sqlite3_result_int(context, x==2 ? 1 : x==4 ? 2 : 0);
+    }
+  }
+  sqlite3_free(p1);
+  sqlite3_free(p2);
+}
 
-  /* 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 */
+/* Objects used by the overlap algorihm. */
+typedef struct GeoEvent GeoEvent;
+typedef struct GeoSegment GeoSegment;
+typedef struct GeoOverlap GeoOverlap;
+struct GeoEvent {
+  double x;              /* X coordinate at which event occurs */
+  int eType;             /* 0 for ADD, 1 for REMOVE */
+  GeoSegment *pSeg;      /* The segment to be added or removed */
+  GeoEvent *pNext;       /* Next event in the sorted list */
+};
+struct GeoSegment {
+  double C, B;           /* y = C*x + B */
+  double y;              /* Current y value */
+  float y0;              /* Initial y value */
+  unsigned char side;    /* 1 for p1, 2 for p2 */
+  unsigned int idx;      /* Which segment within the side */
+  GeoSegment *pNext;     /* Next segment in a list sorted by y */
+};
+struct GeoOverlap {
+  GeoEvent *aEvent;          /* Array of all events */
+  GeoSegment *aSegment;      /* Array of all segments */
+  int nEvent;                /* Number of events */
+  int nSegment;              /* Number of segments */
+};
 
-  /* 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 */
+/*
+** Add a single segment and its associated events.
+*/
+static void geopolyAddOneSegment(
+  GeoOverlap *p,
+  GeoCoord x0,
+  GeoCoord y0,
+  GeoCoord x1,
+  GeoCoord y1,
+  unsigned char side,
+  unsigned int idx
+){
+  GeoSegment *pSeg;
+  GeoEvent *pEvent;
+  if( x0==x1 ) return;  /* Ignore vertical segments */
+  if( x0>x1 ){
+    GeoCoord t = x0;
+    x0 = x1;
+    x1 = t;
+    t = y0;
+    y0 = y1;
+    y1 = t;
+  }
+  pSeg = p->aSegment + p->nSegment;
+  p->nSegment++;
+  pSeg->C = (y1-y0)/(x1-x0);
+  pSeg->B = y1 - x1*pSeg->C;
+  pSeg->y0 = y0;
+  pSeg->side = side;
+  pSeg->idx = idx;
+  pEvent = p->aEvent + p->nEvent;
+  p->nEvent++;
+  pEvent->x = x0;
+  pEvent->eType = 0;
+  pEvent->pSeg = pSeg;
+  pEvent = p->aEvent + p->nEvent;
+  p->nEvent++;
+  pEvent->x = x1;
+  pEvent->eType = 1;
+  pEvent->pSeg = pSeg;
+}
+  
 
-  /* 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.
+** Insert all segments and events for polygon pPoly.
 */
-#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
-
+static void geopolyAddSegments(
+  GeoOverlap *p,          /* Add segments to this Overlap object */
+  GeoPoly *pPoly,         /* Take all segments from this polygon */
+  unsigned char side      /* The side of pPoly */
+){
+  unsigned int i;
+  GeoCoord *x;
+  for(i=0; i<(unsigned)pPoly->nVertex-1; i++){
+    x = pPoly->a + (i*2);
+    geopolyAddOneSegment(p, x[0], x[1], x[2], x[3], side, i);
+  }
+  x = pPoly->a + (i*2);
+  geopolyAddOneSegment(p, x[0], x[1], pPoly->a[0], pPoly->a[1], side, i);
+}
 
 /*
-** Within the RBU_STAGE_OAL stage, each call to sqlite3rbu_step() performs
-** one of the following operations.
+** Merge two lists of sorted events by X coordinate
 */
-#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 */
+static GeoEvent *geopolyEventMerge(GeoEvent *pLeft, GeoEvent *pRight){
+  GeoEvent head, *pLast;
+  head.pNext = 0;
+  pLast = &head;
+  while( pRight && pLeft ){
+    if( pRight->x <= pLeft->x ){
+      pLast->pNext = pRight;
+      pLast = pRight;
+      pRight = pRight->pNext;
+    }else{
+      pLast->pNext = pLeft;
+      pLast = pLeft;
+      pLeft = pLeft->pNext;
+    }
+  }
+  pLast->pNext = pRight ? pRight : pLeft;
+  return head.pNext;  
+}
 
-#define RBU_UPDATE     6          /* Update a row in a main table b-tree */
+/*
+** Sort an array of nEvent event objects into a list.
+*/
+static GeoEvent *geopolySortEventsByX(GeoEvent *aEvent, int nEvent){
+  int mx = 0;
+  int i, j;
+  GeoEvent *p;
+  GeoEvent *a[50];
+  for(i=0; i<nEvent; i++){
+    p = &aEvent[i];
+    p->pNext = 0;
+    for(j=0; j<mx && a[j]; j++){
+      p = geopolyEventMerge(a[j], p);
+      a[j] = 0;
+    }
+    a[j] = p;
+    if( j>=mx ) mx = j+1;
+  }
+  p = 0;
+  for(i=0; i<mx; i++){
+    p = geopolyEventMerge(a[i], p);
+  }
+  return p;
+}
 
 /*
-** A single step of an incremental checkpoint - frame iWalFrame of the wal
-** file should be copied to page iDbPage of the database file.
+** Merge two lists of sorted segments by Y, and then by C.
 */
-struct RbuFrame {
-  u32 iDbPage;
-  u32 iWalFrame;
-};
+static GeoSegment *geopolySegmentMerge(GeoSegment *pLeft, GeoSegment *pRight){
+  GeoSegment head, *pLast;
+  head.pNext = 0;
+  pLast = &head;
+  while( pRight && pLeft ){
+    double r = pRight->y - pLeft->y;
+    if( r==0.0 ) r = pRight->C - pLeft->C;
+    if( r<0.0 ){
+      pLast->pNext = pRight;
+      pLast = pRight;
+      pRight = pRight->pNext;
+    }else{
+      pLast->pNext = pLeft;
+      pLast = pLeft;
+      pLeft = pLeft->pNext;
+    }
+  }
+  pLast->pNext = pRight ? pRight : pLeft;
+  return head.pNext;  
+}
 
 /*
-** 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.
+** Sort a list of GeoSegments in order of increasing Y and in the event of
+** a tie, increasing C (slope).
 */
-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;
+static GeoSegment *geopolySortSegmentsByYAndC(GeoSegment *pList){
+  int mx = 0;
+  int i;
+  GeoSegment *p;
+  GeoSegment *a[50];
+  while( pList ){
+    p = pList;
+    pList = pList->pNext;
+    p->pNext = 0;
+    for(i=0; i<mx && a[i]; i++){
+      p = geopolySegmentMerge(a[i], p);
+      a[i] = 0;
+    }
+    a[i] = p;
+    if( i>=mx ) mx = i+1;
+  }
+  p = 0;
+  for(i=0; i<mx; i++){
+    p = geopolySegmentMerge(a[i], p);
+  }
+  return p;
+}
 
-  /* 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;
-  i64 szTemp;                     /* Current size of all temp files in use */
-  i64 szTempLimit;                /* Total size limit for temp files */
+/*
+** Determine the overlap between two polygons
+*/
+static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2){
+  int nVertex = p1->nVertex + p2->nVertex + 2;
+  GeoOverlap *p;
+  int nByte;
+  GeoEvent *pThisEvent;
+  double rX;
+  int rc = 0;
+  int needSort = 0;
+  GeoSegment *pActive = 0;
+  GeoSegment *pSeg;
+  unsigned char aOverlap[4];
+
+  nByte = sizeof(GeoEvent)*nVertex*2 
+           + sizeof(GeoSegment)*nVertex 
+           + sizeof(GeoOverlap);
+  p = sqlite3_malloc( nByte );
+  if( p==0 ) return -1;
+  p->aEvent = (GeoEvent*)&p[1];
+  p->aSegment = (GeoSegment*)&p->aEvent[nVertex*2];
+  p->nEvent = p->nSegment = 0;
+  geopolyAddSegments(p, p1, 1);
+  geopolyAddSegments(p, p2, 2);
+  pThisEvent = geopolySortEventsByX(p->aEvent, p->nEvent);
+  rX = pThisEvent->x==0.0 ? -1.0 : 0.0;
+  memset(aOverlap, 0, sizeof(aOverlap));
+  while( pThisEvent ){
+    if( pThisEvent->x!=rX ){
+      GeoSegment *pPrev = 0;
+      int iMask = 0;
+      GEODEBUG(("Distinct X: %g\n", pThisEvent->x));
+      rX = pThisEvent->x;
+      if( needSort ){
+        GEODEBUG(("SORT\n"));
+        pActive = geopolySortSegmentsByYAndC(pActive);
+        needSort = 0;
+      }
+      for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){
+        if( pPrev ){
+          if( pPrev->y!=pSeg->y ){
+            GEODEBUG(("MASK: %d\n", iMask));
+            aOverlap[iMask] = 1;
+          }
+        }
+        iMask ^= pSeg->side;
+        pPrev = pSeg;
+      }
+      pPrev = 0;
+      for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){
+        double y = pSeg->C*rX + pSeg->B;
+        GEODEBUG(("Segment %d.%d %g->%g\n", pSeg->side, pSeg->idx, pSeg->y, y));
+        pSeg->y = y;
+        if( pPrev ){
+          if( pPrev->y>pSeg->y && pPrev->side!=pSeg->side ){
+            rc = 1;
+            GEODEBUG(("Crossing: %d.%d and %d.%d\n",
+                    pPrev->side, pPrev->idx,
+                    pSeg->side, pSeg->idx));
+            goto geopolyOverlapDone;
+          }else if( pPrev->y!=pSeg->y ){
+            GEODEBUG(("MASK: %d\n", iMask));
+            aOverlap[iMask] = 1;
+          }
+        }
+        iMask ^= pSeg->side;
+        pPrev = pSeg;
+      }
+    }
+    GEODEBUG(("%s %d.%d C=%g B=%g\n",
+      pThisEvent->eType ? "RM " : "ADD",
+      pThisEvent->pSeg->side, pThisEvent->pSeg->idx,
+      pThisEvent->pSeg->C,
+      pThisEvent->pSeg->B));
+    if( pThisEvent->eType==0 ){
+      /* Add a segment */
+      pSeg = pThisEvent->pSeg;
+      pSeg->y = pSeg->y0;
+      pSeg->pNext = pActive;
+      pActive = pSeg;
+      needSort = 1;
+    }else{
+      /* Remove a segment */
+      if( pActive==pThisEvent->pSeg ){
+        pActive = pActive->pNext;
+      }else{
+        for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){
+          if( pSeg->pNext==pThisEvent->pSeg ){
+            pSeg->pNext = pSeg->pNext->pNext;
+            break;
+          }
+        }
+      }
+    }
+    pThisEvent = pThisEvent->pNext;
+  }
+  if( aOverlap[3]==0 ){
+    rc = 0;
+  }else if( aOverlap[1]!=0 && aOverlap[2]==0 ){
+    rc = 3;
+  }else if( aOverlap[1]==0 && aOverlap[2]!=0 ){
+    rc = 2;
+  }else if( aOverlap[1]==0 && aOverlap[2]==0 ){
+    rc = 4;
+  }else{
+    rc = 1;
+  }
 
-  /* Used in RBU vacuum mode only */
-  int nRbu;                       /* Number of RBU VFS in the stack */
-  rbu_file *pRbuFd;               /* Fd for main db of dbRbu */
-};
+geopolyOverlapDone:
+  sqlite3_free(p);
+  return rc;
+}
 
 /*
-** An rbu VFS is implemented using an instance of this structure.
+** SQL function:    geopoly_overlap(P1,P2)
 **
-** Variable pRbu is only non-NULL for automatically created RBU VFS objects.
-** It is NULL for RBU VFS objects created explicitly using
-** sqlite3rbu_create_vfs(). It is used to track the total amount of temp
-** space used by the RBU handle.
+** Determine whether or not P1 and P2 overlap. Return value:
+**
+**   0     The two polygons are disjoint
+**   1     They overlap
+**   2     P1 is completely contained within P2
+**   3     P2 is completely contained within P1
+**   4     P1 and P2 are the same polygon
+**   NULL  Either P1 or P2 or both are not valid polygons
 */
-struct rbu_vfs {
-  sqlite3_vfs base;               /* rbu VFS shim methods */
-  sqlite3_vfs *pRealVfs;          /* Underlying VFS */
-  sqlite3_mutex *mutex;           /* Mutex to protect pMain */
-  sqlite3rbu *pRbu;               /* Owner RBU object */
-  rbu_file *pMain;                /* Linked list of main db files */
-};
+static void geopolyOverlapFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0);
+  GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0);
+  if( p1 && p2 ){
+    int x = geopolyOverlap(p1, p2);
+    if( x<0 ){
+      sqlite3_result_error_nomem(context);
+    }else{
+      sqlite3_result_int(context, x);
+    }
+  }
+  sqlite3_free(p1);
+  sqlite3_free(p2);
+}
 
 /*
-** Each file opened by an rbu VFS is represented by an instance of
-** the following structure.
+** Enable or disable debugging output
+*/
+static void geopolyDebugFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+#ifdef GEOPOLY_ENABLE_DEBUG
+  geo_debug = sqlite3_value_int(argv[0]);
+#endif
+}
+
+/* 
+** This function is the implementation of both the xConnect and xCreate
+** methods of the geopoly virtual table.
 **
-** If this is a temporary file (pRbu!=0 && flags&DELETE_ON_CLOSE), variable
-** "sz" is set to the current size of the database file.
+**   argv[0]   -> module name
+**   argv[1]   -> database name
+**   argv[2]   -> table name
+**   argv[...] -> column names...
 */
-struct rbu_file {
-  sqlite3_file base;              /* sqlite3_file methods */
-  sqlite3_file *pReal;            /* Underlying file handle */
-  rbu_vfs *pRbuVfs;               /* Pointer to the rbu_vfs object */
-  sqlite3rbu *pRbu;               /* Pointer to rbu object (rbu target only) */
-  i64 sz;                         /* Size of file in bytes (temp only) */
+static int geopolyInit(
+  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] */
+  sqlite3_str *pSql;
+  char *zSql;
+  int ii;
 
-  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 */
+  sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
 
-  int nShm;                       /* Number of entries in apShm[] array */
-  char **apShm;                   /* Array of mmap'd *-shm regions */
-  char *zDel;                     /* Delete this when closing file */
+  /* 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->eCoordType = RTREE_COORD_REAL32;
+  pRtree->nDim = 2;
+  pRtree->nDim2 = 4;
+  memcpy(pRtree->zDb, argv[1], nDb);
+  memcpy(pRtree->zName, argv[2], nName);
 
-  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.
+  /* Create/Connect to the underlying relational database schema. If
+  ** that is successful, call sqlite3_declare_vtab() to configure
+  ** the r-tree table schema.
+  */
+  pSql = sqlite3_str_new(db);
+  sqlite3_str_appendf(pSql, "CREATE TABLE x(_shape");
+  pRtree->nAux = 1;         /* Add one for _shape */
+  pRtree->nAuxNotNull = 1;  /* The _shape column is always not-null */
+  for(ii=3; ii<argc; ii++){
+    pRtree->nAux++;
+    sqlite3_str_appendf(pSql, ",%s", argv[ii]);
+  }
+  sqlite3_str_appendf(pSql, ");");
+  zSql = sqlite3_str_finish(pSql);
+  if( !zSql ){
+    rc = SQLITE_NOMEM;
+  }else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){
+    *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+  }
+  sqlite3_free(zSql);
+  if( rc ) goto geopolyInit_fail;
+  pRtree->nBytesPerCell = 8 + pRtree->nDim2*4;
+
+  /* Figure out the node size to use. */
+  rc = getNodeSize(db, pRtree, isCreate, pzErr);
+  if( rc ) goto geopolyInit_fail;
+  rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate);
+  if( rc ){
+    *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+    goto geopolyInit_fail;
+  }
+
+  *ppVtab = (sqlite3_vtab *)pRtree;
+  return SQLITE_OK;
+
+geopolyInit_fail:
+  if( rc==SQLITE_OK ) rc = SQLITE_ERROR;
+  assert( *ppVtab==0 );
+  assert( pRtree->nBusy==1 );
+  rtreeRelease(pRtree);
+  return rc;
+}
+
+
+/* 
+** GEOPOLY virtual table module xCreate method.
 */
-#define rbuIsVacuum(p) ((p)->zTarget==0)
+static int geopolyCreate(
+  sqlite3 *db,
+  void *pAux,
+  int argc, const char *const*argv,
+  sqlite3_vtab **ppVtab,
+  char **pzErr
+){
+  return geopolyInit(db, pAux, argc, argv, ppVtab, pzErr, 1);
+}
+
+/* 
+** GEOPOLY virtual table module xConnect method.
+*/
+static int geopolyConnect(
+  sqlite3 *db,
+  void *pAux,
+  int argc, const char *const*argv,
+  sqlite3_vtab **ppVtab,
+  char **pzErr
+){
+  return geopolyInit(db, pAux, argc, argv, ppVtab, pzErr, 0);
+}
 
 
-/*************************************************************************
-** The following three functions, found below:
+/* 
+** GEOPOLY virtual table module xFilter method.
 **
-**   rbuDeltaGetInt()
-**   rbuDeltaChecksum()
-**   rbuDeltaApply()
+** Query plans:
 **
-** are lifted from the fossil source code (http://fossil-scm.org). They
-** are used to implement the scalar SQL function rbu_fossil_delta().
+**      1         rowid lookup
+**      2         search for objects overlapping the same bounding box
+**                that contains polygon argv[0]
+**      3         search for objects overlapping the same bounding box
+**                that contains polygon argv[0]
+**      4         full table scan
 */
+static int geopolyFilter(
+  sqlite3_vtab_cursor *pVtabCursor,     /* The cursor to initialize */
+  int idxNum,                           /* Query plan */
+  const char *idxStr,                   /* Not Used */
+  int argc, sqlite3_value **argv        /* Parameters to the query plan */
+){
+  Rtree *pRtree = (Rtree *)pVtabCursor->pVtab;
+  RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor;
+  RtreeNode *pRoot = 0;
+  int rc = SQLITE_OK;
+  int iCell = 0;
+  sqlite3_stmt *pStmt;
 
-/*
-** 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;
+  rtreeReference(pRtree);
+
+  /* Reset the cursor to the same state as rtreeOpen() leaves it in. */
+  freeCursorConstraints(pCsr);
+  sqlite3_free(pCsr->aPoint);
+  pStmt = pCsr->pReadAux;
+  memset(pCsr, 0, sizeof(RtreeCursor));
+  pCsr->base.pVtab = (sqlite3_vtab*)pRtree;
+  pCsr->pReadAux = pStmt;
+
+  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 && idxNum<=3 ){
+      RtreeCoord bbox[4];
+      RtreeConstraint *p;
+      assert( argc==1 );
+      geopolyBBox(0, argv[0], bbox, &rc);
+      if( rc ){
+        goto geopoly_filter_end;
+      }
+      pCsr->aConstraint = p = sqlite3_malloc(sizeof(RtreeConstraint)*4);
+      pCsr->nConstraint = 4;
+      if( p==0 ){
+        rc = SQLITE_NOMEM;
+      }else{
+        memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*4);
+        memset(pCsr->anQueue, 0, sizeof(u32)*(pRtree->iDepth + 1));
+        if( idxNum==2 ){
+          /* Overlap query */
+          p->op = 'B';
+          p->iCoord = 0;
+          p->u.rValue = bbox[1].f;
+          p++;
+          p->op = 'D';
+          p->iCoord = 1;
+          p->u.rValue = bbox[0].f;
+          p++;
+          p->op = 'B';
+          p->iCoord = 2;
+          p->u.rValue = bbox[3].f;
+          p++;
+          p->op = 'D';
+          p->iCoord = 3;
+          p->u.rValue = bbox[2].f;
+        }else{
+          /* Within query */
+          p->op = 'D';
+          p->iCoord = 0;
+          p->u.rValue = bbox[0].f;
+          p++;
+          p->op = 'B';
+          p->iCoord = 1;
+          p->u.rValue = bbox[1].f;
+          p++;
+          p->op = 'D';
+          p->iCoord = 2;
+          p->u.rValue = bbox[2].f;
+          p++;
+          p->op = 'B';
+          p->iCoord = 3;
+          p->u.rValue = bbox[3].f;
+        }
+      }
+    }
+    if( rc==SQLITE_OK ){
+      RtreeSearchPoint *pNew;
+      pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1));
+      if( pNew==0 ){
+        rc = SQLITE_NOMEM;
+        goto geopoly_filter_end;
+      }
+      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);
+    }
   }
-  z--;
-  *pLen -= z - zStart;
-  *pz = (char*)z;
-  return v;
+
+geopoly_filter_end:
+  nodeRelease(pRtree, pRoot);
+  rtreeRelease(pRtree);
+  return rc;
 }
 
-#if RBU_ENABLE_DELTA_CKSUM
 /*
-** Compute a 32-bit checksum on the N-byte buffer.  Return the result.
+** 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        "rowid"       Direct lookup by rowid.
+**     2        "rtree"       R-tree overlap query using geopoly_overlap()
+**     3        "rtree"       R-tree within query using geopoly_within()
+**     4        "fullscan"    full-table scan.
+**   ------------------------------------------------
 */
-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;
+static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
+  int ii;
+  int iRowidTerm = -1;
+  int iFuncTerm = -1;
+  int idxNum = 0;
+
+  for(ii=0; ii<pIdxInfo->nConstraint; ii++){
+    struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];
+    if( !p->usable ) continue;
+    if( p->iColumn<0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ  ){
+      iRowidTerm = ii;
+      break;
+    }
+    if( p->iColumn==0 && p->op>=SQLITE_INDEX_CONSTRAINT_FUNCTION ){
+      /* p->op==SQLITE_INDEX_CONSTRAINT_FUNCTION for geopoly_overlap()
+      ** p->op==(SQLITE_INDEX_CONTRAINT_FUNCTION+1) for geopoly_within().
+      ** See geopolyFindFunction() */
+      iFuncTerm = ii;
+      idxNum = p->op - SQLITE_INDEX_CONSTRAINT_FUNCTION + 2;
+    }
   }
-  while(N >= 4){
-    sum0 += z[0];
-    sum1 += z[1];
-    sum2 += z[2];
-    sum3 += z[3];
-    z += 4;
-    N -= 4;
+
+  if( iRowidTerm>=0 ){
+    pIdxInfo->idxNum = 1;
+    pIdxInfo->idxStr = "rowid";
+    pIdxInfo->aConstraintUsage[iRowidTerm].argvIndex = 1;
+    pIdxInfo->aConstraintUsage[iRowidTerm].omit = 1;
+    pIdxInfo->estimatedCost = 30.0;
+    pIdxInfo->estimatedRows = 1;
+    pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
+    return SQLITE_OK;
   }
-  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:  ;
+  if( iFuncTerm>=0 ){
+    pIdxInfo->idxNum = idxNum;
+    pIdxInfo->idxStr = "rtree";
+    pIdxInfo->aConstraintUsage[iFuncTerm].argvIndex = 1;
+    pIdxInfo->aConstraintUsage[iFuncTerm].omit = 0;
+    pIdxInfo->estimatedCost = 300.0;
+    pIdxInfo->estimatedRows = 10;
+    return SQLITE_OK;
   }
-  return sum3;
+  pIdxInfo->idxNum = 4;
+  pIdxInfo->idxStr = "fullscan";
+  pIdxInfo->estimatedCost = 3000000.0;
+  pIdxInfo->estimatedRows = 100000;
+  return SQLITE_OK;
 }
-#endif
+
+
+/* 
+** GEOPOLY virtual table module xColumn method.
+*/
+static int geopolyColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
+  Rtree *pRtree = (Rtree *)cur->pVtab;
+  RtreeCursor *pCsr = (RtreeCursor *)cur;
+  RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr);
+  int rc = SQLITE_OK;
+  RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc);
+
+  if( rc ) return rc;
+  if( p==0 ) return SQLITE_OK;
+  if( i==0 && sqlite3_vtab_nochange(ctx) ) return SQLITE_OK;
+  if( i<=pRtree->nAux ){
+    if( !pCsr->bAuxValid ){
+      if( pCsr->pReadAux==0 ){
+        rc = sqlite3_prepare_v3(pRtree->db, pRtree->zReadAuxSql, -1, 0,
+                                &pCsr->pReadAux, 0);
+        if( rc ) return rc;
+      }
+      sqlite3_bind_int64(pCsr->pReadAux, 1, 
+          nodeGetRowid(pRtree, pNode, p->iCell));
+      rc = sqlite3_step(pCsr->pReadAux);
+      if( rc==SQLITE_ROW ){
+        pCsr->bAuxValid = 1;
+      }else{
+        sqlite3_reset(pCsr->pReadAux);
+        if( rc==SQLITE_DONE ) rc = SQLITE_OK;
+        return rc;
+      }
+    }
+    sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pReadAux, i+2));
+  }
+  return SQLITE_OK;
+}
+
 
 /*
-** Apply a delta.
+** The xUpdate method for GEOPOLY module virtual tables.
 **
-** 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.
+** For DELETE:
 **
-** 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.
+**     argv[0] = the rowid to be deleted
 **
-** 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.
+** For INSERT:
 **
-** Refer to the delta_create() documentation above for a description
-** of the delta file format.
+**     argv[0] = SQL NULL
+**     argv[1] = rowid to insert, or an SQL NULL to select automatically
+**     argv[2] = _shape column
+**     argv[3] = first application-defined column....
+**
+** For UPDATE:
+**
+**     argv[0] = rowid to modify.  Never NULL
+**     argv[1] = rowid after the change.  Never NULL
+**     argv[2] = new value for _shape
+**     argv[3] = new value for first application-defined column....
 */
-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 */
+static int geopolyUpdate(
+  sqlite3_vtab *pVtab, 
+  int nData, 
+  sqlite3_value **aData, 
+  sqlite_int64 *pRowid
 ){
-  unsigned int limit;
-  unsigned int total = 0;
-#if RBU_ENABLE_DELTA_CKSUM
-  char *zOrigOut = zOut;
-#endif
+  Rtree *pRtree = (Rtree *)pVtab;
+  int rc = SQLITE_OK;
+  RtreeCell cell;                 /* New cell to insert if nData>1 */
+  i64 oldRowid;                   /* The old rowid */
+  int oldRowidValid;              /* True if oldRowid is valid */
+  i64 newRowid;                   /* The new rowid */
+  int newRowidValid;              /* True if newRowid is valid */
+  int coordChange = 0;            /* Change in coordinates */
 
-  limit = rbuDeltaGetInt(&zDelta, &lenDelta);
-  if( *zDelta!='\n' ){
-    /* ERROR: size integer not terminated by "\n" */
-    return -1;
+  if( pRtree->nNodeRef ){
+    /* Unable to write to the btree while another cursor is reading from it,
+    ** since the write might do a rebalance which would disrupt the read
+    ** cursor. */
+    return SQLITE_LOCKED_VTAB;
   }
-  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;
+  rtreeReference(pRtree);
+  assert(nData>=1);
+
+  oldRowidValid = sqlite3_value_type(aData[0])!=SQLITE_NULL;;
+  oldRowid = oldRowidValid ? sqlite3_value_int64(aData[0]) : 0;
+  newRowidValid = nData>1 && sqlite3_value_type(aData[1])!=SQLITE_NULL;
+  newRowid = newRowidValid ? sqlite3_value_int64(aData[1]) : 0;
+  cell.iRowid = newRowid;
+
+  if( nData>1                                 /* not a DELETE */
+   && (!oldRowidValid                         /* INSERT */
+        || !sqlite3_value_nochange(aData[2])  /* UPDATE _shape */
+        || oldRowid!=newRowid)                /* Rowid change */
+  ){
+    geopolyBBox(0, aData[2], cell.aCoord, &rc);
+    if( rc ){
+      if( rc==SQLITE_ERROR ){
+        pVtab->zErrMsg =
+          sqlite3_mprintf("_shape does not contain a valid polygon");
       }
-      case ';': {
-        zDelta++; lenDelta--;
-        zOut[0] = 0;
-#if RBU_ENABLE_DELTA_CKSUM
-        if( cnt!=rbuDeltaChecksum(zOrigOut, total) ){
-          /* ERROR:  bad checksum */
-          return -1;
-        }
-#endif
-        if( total!=limit ){
-          /* ERROR: generated size does not match predicted size */
-          return -1;
+      goto geopoly_update_end;
+    }
+    coordChange = 1;
+
+    /* If a rowid value was supplied, check if it is already present in 
+    ** the table. If so, the constraint has failed. */
+    if( newRowidValid && (!oldRowidValid || oldRowid!=newRowid) ){
+      int steprc;
+      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);
         }
-        return total;
       }
-      default: {
-        /* ERROR: unknown delta operator */
-        return -1;
+    }
+  }
+
+  /* If aData[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( rc==SQLITE_OK && (nData==1 || (coordChange && oldRowidValid)) ){
+    rc = rtreeDeleteRowid(pRtree, oldRowid);
+  }
+
+  /* If the aData[] array contains more than one element, elements
+  ** (aData[2]..aData[argc-1]) contain a new record to insert into
+  ** the r-tree structure.
+  */
+  if( rc==SQLITE_OK && nData>1 && coordChange ){
+    /* Insert the new record into the r-tree */
+    RtreeNode *pLeaf = 0;
+    if( !newRowidValid ){
+      rc = rtreeNewRowid(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;
       }
     }
   }
-  /* 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;
+  /* Change the data */
+  if( rc==SQLITE_OK && nData>1 ){
+    sqlite3_stmt *pUp = pRtree->pWriteAux;
+    int jj;
+    int nChange = 0;
+    sqlite3_bind_int64(pUp, 1, cell.iRowid);
+    assert( pRtree->nAux>=1 );
+    if( sqlite3_value_nochange(aData[2]) ){
+      sqlite3_bind_null(pUp, 2);
+    }else{
+      sqlite3_bind_value(pUp, 2, aData[2]);
+      nChange = 1;
+    }
+    for(jj=1; jj<pRtree->nAux; jj++){
+      nChange++;
+      sqlite3_bind_value(pUp, jj+2, aData[jj+2]);
+    }
+    if( nChange ){
+      sqlite3_step(pUp);
+      rc = sqlite3_reset(pUp);
+    }
   }
-  return size;
-}
 
-/*
-** End of code taken from fossil.
-*************************************************************************/
+geopoly_update_end:
+  rtreeRelease(pRtree);
+  return rc;
+}
 
 /*
-** 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.
+** Report that geopoly_overlap() is an overloaded function suitable
+** for use in xBestIndex.
 */
-static void rbuFossilDeltaFunc(
-  sqlite3_context *context,
-  int argc,
-  sqlite3_value **argv
+static int geopolyFindFunction(
+  sqlite3_vtab *pVtab,
+  int nArg,
+  const char *zName,
+  void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
+  void **ppArg
 ){
-  const char *aDelta;
-  int nDelta;
-  const char *aOrig;
-  int nOrig;
-
-  int nOut;
-  int nOut2;
-  char *aOut;
+  if( sqlite3_stricmp(zName, "geopoly_overlap")==0 ){
+    *pxFunc = geopolyOverlapFunc;
+    *ppArg = 0;
+    return SQLITE_INDEX_CONSTRAINT_FUNCTION;
+  }
+  if( sqlite3_stricmp(zName, "geopoly_within")==0 ){
+    *pxFunc = geopolyWithinFunc;
+    *ppArg = 0;
+    return SQLITE_INDEX_CONSTRAINT_FUNCTION+1;
+  }
+  return 0;
+}
 
-  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]);
+static sqlite3_module geopolyModule = {
+  2,                          /* iVersion */
+  geopolyCreate,              /* xCreate - create a table */
+  geopolyConnect,             /* xConnect - connect to an existing table */
+  geopolyBestIndex,           /* 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 */
+  geopolyFilter,              /* xFilter - configure scan constraints */
+  rtreeNext,                  /* xNext - advance a cursor */
+  rtreeEof,                   /* xEof */
+  geopolyColumn,              /* xColumn - read data */
+  rtreeRowid,                 /* xRowid - read data */
+  geopolyUpdate,              /* xUpdate - write data */
+  rtreeBeginTransaction,      /* xBegin - begin transaction */
+  rtreeEndTransaction,        /* xSync - sync transaction */
+  rtreeEndTransaction,        /* xCommit - commit transaction */
+  rtreeEndTransaction,        /* xRollback - rollback transaction */
+  geopolyFindFunction,        /* xFindFunction - function overloading */
+  rtreeRename,                /* xRename - rename the table */
+  rtreeSavepoint,             /* xSavepoint */
+  0,                          /* xRelease */
+  0,                          /* xRollbackTo */
+};
 
-  /* Figure out the size of the output */
-  nOut = rbuDeltaOutputSize(aDelta, nDelta);
-  if( nOut<0 ){
-    sqlite3_result_error(context, "corrupt fossil delta", -1);
-    return;
+static int sqlite3_geopoly_init(sqlite3 *db){
+  int rc = SQLITE_OK;
+  static const struct {
+    void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
+    int nArg;
+    const char *zName;
+  } aFunc[] = {
+     { geopolyAreaFunc,          1,    "geopoly_area"             },
+     { geopolyBlobFunc,          1,    "geopoly_blob"             },
+     { geopolyJsonFunc,          1,    "geopoly_json"             },
+     { geopolySvgFunc,          -1,    "geopoly_svg"              },
+     { geopolyWithinFunc,        2,    "geopoly_within"           },
+     { geopolyContainsPointFunc, 3,    "geopoly_contains_point"   },
+     { geopolyOverlapFunc,       2,    "geopoly_overlap"          },
+     { geopolyDebugFunc,         1,    "geopoly_debug"            },
+     { geopolyBBoxFunc,          1,    "geopoly_bbox"             },
+     { geopolyXformFunc,         7,    "geopoly_xform"            },
+  };
+  static const struct {
+    void (*xStep)(sqlite3_context*,int,sqlite3_value**);
+    void (*xFinal)(sqlite3_context*);
+    const char *zName;
+  } aAgg[] = {
+     { geopolyBBoxStep, geopolyBBoxFinal, "geopoly_group_bbox"    },
+  };
+  int i;
+  for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
+    rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg,
+                                 SQLITE_UTF8, 0,
+                                 aFunc[i].xFunc, 0, 0);
   }
-
-  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);
-    }
+  for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
+    rc = sqlite3_create_function(db, aAgg[i].zName, 1, SQLITE_UTF8, 0,
+                                 0, aAgg[i].xStep, aAgg[i].xFinal);
   }
+  if( rc==SQLITE_OK ){
+    rc = sqlite3_create_module_v2(db, "geopoly", &geopolyModule, 0, 0);
+  }
+  return rc;
 }
 
+/************** End of geopoly.c *********************************************/
+/************** Continuing where we left off in rtree.c **********************/
+#endif
 
 /*
-** 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().
+** Register the r-tree module with database handle db. This creates the
+** virtual table module "rtree" and the debugging/analysis scalar 
+** function "rtreenode".
 */
-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;
+SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db){
+  const int utf8 = SQLITE_UTF8;
+  int rc;
+
+  rc = sqlite3_create_function(db, "rtreenode", 2, utf8, 0, rtreenode, 0, 0);
+  if( rc==SQLITE_OK ){
+    rc = sqlite3_create_function(db, "rtreedepth", 1, utf8, 0,rtreedepth, 0, 0);
   }
+  if( rc==SQLITE_OK ){
+    rc = sqlite3_create_function(db, "rtreecheck", -1, utf8, 0,rtreecheck, 0,0);
+  }
+  if( rc==SQLITE_OK ){
+#ifdef SQLITE_RTREE_INT_ONLY
+    void *c = (void *)RTREE_COORD_INT32;
+#else
+    void *c = (void *)RTREE_COORD_REAL32;
+#endif
+    rc = sqlite3_create_module_v2(db, "rtree", &rtreeModule, c, 0);
+  }
+  if( rc==SQLITE_OK ){
+    void *c = (void *)RTREE_COORD_INT32;
+    rc = sqlite3_create_module_v2(db, "rtree_i32", &rtreeModule, c, 0);
+  }
+#ifdef SQLITE_ENABLE_GEOPOLY
+  if( rc==SQLITE_OK ){
+    rc = sqlite3_geopoly_init(db);
+  }
+#endif
+
   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().
+** This routine deletes the RtreeGeomCallback object that was attached
+** one of the SQL functions create by sqlite3_rtree_geometry_callback()
+** or sqlite3_rtree_query_callback().  In other words, this routine is the
+** destructor for an RtreeGeomCallback objecct.  This routine is called when
+** the corresponding SQL function is deleted.
 */
-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)));
+static void rtreeFreeCallback(void *p){
+  RtreeGeomCallback *pInfo = (RtreeGeomCallback*)p;
+  if( pInfo->xDestructor ) 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; i<p->nParam; i++){
+    sqlite3_value_free(p->apSqlParam[i]);
   }
-  return rc;
+  sqlite3_free(p);
 }
 
 /*
-** 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. 
+** Each call to sqlite3_rtree_geometry_callback() or
+** sqlite3_rtree_query_callback() creates an ordinary SQLite
+** scalar function that is implemented by this routine.
 **
-** 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().
+** 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.
 **
-** 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.
+** 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 int prepareFreeAndCollectError(
-  sqlite3 *db, 
-  sqlite3_stmt **ppStmt,
-  char **pzErrmsg,
-  char *zSql
-){
-  int rc;
-  assert( *pzErrmsg==0 );
-  if( zSql==0 ){
-    rc = SQLITE_NOMEM;
-    *ppStmt = 0;
+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{
-    rc = prepareAndCollectError(db, ppStmt, pzErrmsg, zSql);
-    sqlite3_free(zSql);
+    int i;
+    pBlob->iSize = nBlob;
+    pBlob->cb = pGeomCtx[0];
+    pBlob->apSqlParam = (sqlite3_value**)&pBlob->aParam[nArg];
+    pBlob->nParam = nArg;
+    for(i=0; i<nArg; i++){
+      pBlob->apSqlParam[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_pointer(ctx, pBlob, "RtreeMatchArg", rtreeMatchArgFree);
+    }
   }
-  return rc;
 }
 
 /*
-** Free the RbuObjIter.azTblCol[] and RbuObjIter.abTblPk[] arrays allocated
-** by an earlier call to rbuObjIterCacheTableInfo().
+** Register a new geometry function for use with the r-tree MATCH operator.
 */
-static void rbuObjIterFreeCols(RbuObjIter *pIter){
-  int i;
-  for(i=0; i<pIter->nTblCol; 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 */
+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
+  );
 }
 
 /*
-** Finalize all statements and free all allocations that are specific to
-** the current object (table/index pair).
+** Register a new 2nd-generation geometry function for use with the
+** r-tree MATCH operator.
 */
-static void rbuObjIterClearStatements(RbuObjIter *pIter){
-  RbuUpdateStmt *pUp;
+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 */
 
-  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;
+  /* 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 *********************************************/
 /*
-** Clean up any resources allocated as part of the iterator object passed
-** as the only argument.
+** 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.
 */
-static void rbuObjIterFinalize(RbuObjIter *pIter){
-  rbuObjIterClearStatements(pIter);
-  sqlite3_finalize(pIter->pTblIter);
-  sqlite3_finalize(pIter->pIdxIter);
-  rbuObjIterFreeCols(pIter);
-  memset(pIter, 0, sizeof(RbuObjIter));
-}
+
+#if !defined(SQLITE_CORE)                  \
+ || defined(SQLITE_ENABLE_ICU)             \
+ || defined(SQLITE_ENABLE_ICU_COLLATIONS)
+
+/* Include ICU headers */
+#include <unicode/utypes.h>
+#include <unicode/uregex.h>
+#include <unicode/ustring.h>
+#include <unicode/ucol.h>
+
+/* #include <assert.h> */
+
+#ifndef SQLITE_CORE
+/*   #include "sqlite3ext.h" */
+  SQLITE_EXTENSION_INIT1
+#else
+/*   #include "sqlite3.h" */
+#endif
 
 /*
-** Advance the iterator to the next position.
+** This function is called when an ICU function called from within
+** the implementation of an SQL scalar function returns an error.
 **
-** 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.
+** The scalar function context passed as the first argument is 
+** loaded with an error message based on the following two args.
 */
-static int rbuObjIterNext(sqlite3rbu *p, RbuObjIter *pIter){
-  int rc = p->rc;
-  if( rc==SQLITE_OK ){
+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);
+}
 
-    /* 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 !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
 
-    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);
+/*
+** 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 uint32_t MATCH_ONE = (uint32_t)'_';
+  static const uint32_t MATCH_ALL = (uint32_t)'%';
+
+  int prevEscape = 0;     /* True if the previous character was uEsc */
+
+  while( 1 ){
+
+    /* Read (and consume) the next character from the input pattern. */
+    uint32_t 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);
         }
-        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;
-          }
+        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==(uint32_t)uEsc){
+      /* Case 3. */
+      prevEscape = 1;
+
+    }else{
+      /* Case 4. */
+      uint32_t uString;
+      SQLITE_ICU_READ_UTF8(zString, uString);
+      uString = (uint32_t)u_foldCase((UChar32)uString, U_FOLD_CASE_DEFAULT);
+      uPattern = (uint32_t)u_foldCase((UChar32)uPattern, U_FOLD_CASE_DEFAULT);
+      if( uString!=uPattern ){
+        return 0;
       }
+      prevEscape = 0;
     }
   }
 
-  if( rc!=SQLITE_OK ){
-    rbuObjIterFinalize(pIter);
-    p->rc = rc;
-  }
-  return rc;
+  return *zString==0;
 }
 
-
 /*
-** 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:
+** 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:
 **
-**     data[0-9]_<name>
+**       A LIKE B
 **
-** where <name> is any sequence of 1 or more characters, <name> is returned.
-** Otherwise, if the only argument does not match the above pattern, an SQL
-** NULL is returned.
+** is implemented as like(B, A). If there is an escape character E, 
 **
-**     "data_t1"     -> "t1"
-**     "data0123_t2" -> "t2"
-**     "dataAB_t3"   -> NULL
+**       A LIKE B ESCAPE E
 **
-** 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).
+** is mapped to like(B, A, E).
 */
-static void rbuTargetNameFunc(
-  sqlite3_context *pCtx,
-  int argc,
+static void icuLikeFunc(
+  sqlite3_context *context, 
+  int argc, 
   sqlite3_value **argv
 ){
-  sqlite3rbu *p = sqlite3_user_data(pCtx);
-  const char *zIn;
-  assert( argc==1 || argc==2 );
+  const unsigned char *zA = sqlite3_value_text(argv[0]);
+  const unsigned char *zB = sqlite3_value_text(argv[1]);
+  UChar32 uEsc = 0;
 
-  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);
-        }
-      }
+  /* 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));
+  }
 }
 
 /*
-** Initialize the iterator structure passed as the second argument.
+** 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.
 **
-** 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.
+** 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 int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){
-  int rc;
-  memset(pIter, 0, sizeof(RbuObjIter));
+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]);
 
-  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" : ""));
+  (void)nArg;  /* Unused parameter */
 
-  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 = ?"
-    );
+  /* If the left hand side of the regexp operator is NULL, 
+  ** then the result is also NULL. 
+  */
+  if( !zString ){
+    return;
   }
 
-  pIter->bCleanup = 1;
-  p->rc = rc;
-  return rbuObjIterNext(p, pIter);
-}
+  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);
 
-/*
-** 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;
+    if( U_SUCCESS(status) ){
+      sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete);
+    }else{
+      assert(!pExpr);
+      icuFunctionError(p, "uregex_open", status);
+      return;
+    }
   }
-  va_end(ap);
-  return zSql;
+
+  /* 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);
 }
 
 /*
-** 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.
+** 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).
 **
-** 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.
+** 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 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;
+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{
-      p->rc = sqlite3_exec(db, zSql, 0, 0, &p->zErrmsg);
+      nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
     }
-  }
-  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;
+    if( U_SUCCESS(status) ){
+      sqlite3_result_text16(p, zOutput, nOut, xFree);
+    }else if( status==U_BUFFER_OVERFLOW_ERROR ){
+      assert( cnt==0 );
+      continue;
     }else{
-      memset(pRet, 0, nByte);
+      icuFunctionError(p, bToUpper ? "u_strToUpper" : "u_strToLower", status);
     }
+    return;
   }
-  return pRet;
+  assert( 0 );     /* Unreachable */
 }
 
+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
 
 /*
-** 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.
+** Collation sequence destructor function. The pCtx argument points to
+** a UCollator structure previously allocated using ucol_open().
 */
-static void rbuAllocateIterArrays(sqlite3rbu *p, RbuObjIter *pIter, int nCol){
-  int nByte = (2*sizeof(char*) + sizeof(int) + 3*sizeof(u8)) * nCol;
-  char **azNew;
+static void icuCollationDel(void *pCtx){
+  UCollator *p = (UCollator *)pCtx;
+  ucol_close(p);
+}
 
-  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];
+/*
+** 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;
 }
 
 /*
-** 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().
+** Implementation of the scalar function icu_load_collation().
 **
-** 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.
+** 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(<locale>, <collation-name>);
+**
+** Where <locale> is a string containing an ICU locale identifier (i.e.
+** "en_AU", "tr_TR" etc.) and <collation-name> is the name of the
+** collation sequence to create.
 */
-static char *rbuStrndup(const char *zStr, int *pRc){
-  char *zRet = 0;
+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( *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;
-    }
+  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;
   }
 
-  return zRet;
+  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);
+  }
 }
 
 /*
-** 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.
+** Register the ICU extension functions with database db.
 */
-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));
+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},
+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
+    {"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},
+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
+  };
+  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;
 }
 
-/* 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.
+#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
 **
-**   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.
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
 **
-** ALGORITHM:
+**    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.
 **
-**   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
-**   }
+*************************************************************************
+** This file implements a tokenizer for fts3 based on the ICU library.
 */
-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};
+/* #include "fts3Int.h" */
+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
+#ifdef SQLITE_ENABLE_ICU
 
-  *peType = RBU_PK_NOTABLE;
-  *piPk = 0;
+/* #include <assert.h> */
+/* #include <string.h> */
+/* #include "fts3_tokenizer.h" */
 
-  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;
+#include <unicode/ubrk.h>
+/* #include <unicode/ucol.h> */
+/* #include <unicode/ustring.h> */
+#include <unicode/utf16.h>
+
+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;
   }
-  if( sqlite3_column_int(aStmt[0], 0) ){
-    *peType = RBU_PK_VTAB;                     /* virtual table */
-    goto rbuTableType_end;
+  p = (IcuTokenizer *)sqlite3_malloc(sizeof(IcuTokenizer)+n);
+  if( !p ){
+    return SQLITE_NOMEM;
   }
-  *piTnum = sqlite3_column_int(aStmt[0], 1);
+  memset(p, 0, sizeof(IcuTokenizer));
 
-  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;
-    }
+  if( n ){
+    p->zLocale = (char *)&p[1];
+    memcpy(p->zLocale, argv[0], n);
   }
 
-  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;
-  }
+  *ppTokenizer = (sqlite3_tokenizer *)p;
 
-rbuTableType_end: {
-    unsigned int i;
-    for(i=0; i<sizeof(aStmt)/sizeof(aStmt[0]); i++){
-      rbuFinalize(p, aStmt[i]);
-    }
-  }
+  return SQLITE_OK;
 }
 
 /*
-** This is a helper function for rbuObjIterCacheTableInfo(). It populates
-** the pIter->abIndexed[] array.
+** Destroy a tokenizer
 */
-static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){
-  sqlite3_stmt *pList = 0;
-  int bIndex = 0;
+static int icuDestroy(sqlite3_tokenizer *pTokenizer){
+  IcuTokenizer *p = (IcuTokenizer *)pTokenizer;
+  sqlite3_free(p);
+  return SQLITE_OK;
+}
 
-  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)
-    );
+/*
+** 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];
 
-  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;
+  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( iInput<nInput ){
+      U8_NEXT(zInput, iInput, nInput, c);
+    }else{
+      c = 0;
     }
-    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--;
+  pCsr->pIter = ubrk_open(UBRK_WORD, p->zLocale, pCsr->aChar, iOut, &status);
+  if( !U_SUCCESS(status) ){
+    sqlite3_free(pCsr);
+    return SQLITE_ERROR;
   }
+  pCsr->nChar = iOut;
 
-  rbuFinalize(p, pList);
-  if( bIndex==0 ) pIter->abIndexed = 0;
+  ubrk_first(pCsr->pIter);
+  *ppCursor = (sqlite3_tokenizer_cursor *)pCsr;
+  return SQLITE_OK;
 }
 
-
 /*
-** 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.
+** Close a tokenization cursor previously opened by a call to icuOpen().
 */
-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;
+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;
+}
 
-    /* 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;
+/*
+** 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;
 
-    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
-    );
+  int iStart = 0;
+  int iEnd = 0;
+  int nByte = 0;
 
-    /* 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 && i<nCol; i++){
-      const char *zName = (const char*)sqlite3_column_name(pStmt, i);
-      if( sqlite3_strnicmp("rbu_", zName, 4) ){
-        char *zCopy = rbuStrndup(zName, &p->rc);
-        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;
+  while( iStart==iEnd ){
+    UChar32 c;
 
-    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")
-      );
+    iStart = ubrk_current(pCsr->pIter);
+    iEnd = ubrk_next(pCsr->pIter);
+    if( iEnd==UBRK_DONE ){
+      return SQLITE_DONE;
     }
 
-    /* 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; i<pIter->nTblCol; 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
-        );
+    while( iStart<iEnd ){
+      int iWhite = iStart;
+      U16_NEXT(pCsr->aChar, iWhite, pCsr->nChar, c);
+      if( u_isspace(c) ){
+        iStart = iWhite;
       }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]);
-        }
+        break;
+      }
+    }
+    assert(iStart<=iEnd);
+  }
 
-        pIter->azTblType[iOrder] = rbuStrndup(zType, &p->rc);
-        pIter->abTblPk[iOrder] = (iPk!=0);
-        pIter->abNotNull[iOrder] = (u8)bNotNull || (iPk!=0);
-        iOrder++;
+  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;
     }
 
-    rbuFinalize(p, pStmt);
-    rbuObjIterCacheIndexedCols(p, pIter);
-    assert( pIter->eType!=RBU_PK_VTAB || pIter->abIndexed==0 );
-    assert( pIter->eType!=RBU_PK_VTAB || pIter->nIndex==0 );
-  }
+    u_strToUTF8(
+        pCsr->zBuffer, pCsr->nBuffer, &nByte,    /* Output vars */
+        &pCsr->aChar[iStart], iEnd-iStart,       /* Input vars */
+        &status                                  /* Output success/failure */
+    );
+  } while( nByte>pCsr->nBuffer );
 
-  return p->rc;
+  *ppToken = pCsr->zBuffer;
+  *pnBytes = nByte;
+  *piStartOffset = pCsr->aOffset[iStart];
+  *piEndOffset = pCsr->aOffset[iEnd];
+  *piPosition = pCsr->iToken++;
+
+  return SQLITE_OK;
 }
 
 /*
-** 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.
+** The set of routines that implement the simple tokenizer
 */
-static char *rbuObjIterGetCollist(
-  sqlite3rbu *p,                  /* RBU object */
-  RbuObjIter *pIter               /* Object iterator for column names */
+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
 ){
-  char *zList = 0;
-  const char *zSep = "";
-  int i;
-  for(i=0; i<pIter->nTblCol; i++){
-    const char *z = pIter->azTblCol[i];
-    zList = rbuMPrintf(p, "%z%s\"%w\"", zList, zSep, z);
-    zSep = ", ";
-  }
-  return zList;
+  *ppModule = &icuTokenizerModule;
 }
 
+#endif /* defined(SQLITE_ENABLE_ICU) */
+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */
+
+/************** End of fts3_icu.c ********************************************/
+/************** Begin file sqlite3rbu.c **************************************/
 /*
-** This function is used to create a SELECT list (the list of SQL 
-** expressions that follows a SELECT keyword) for a SELECT statement 
-** used to read from an data_xxx or rbu_tmp_xxx table while updating the 
-** index object currently indicated by the iterator object passed as the 
-** second argument. A "PRAGMA index_xinfo = <idxname>" statement is used 
-** to obtain the required information.
+** 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 "<database>-oal" instead of "<database>-wal".
+**     Because regular SQLite clients do not look for file named
+**     "<database>-oal", they go on using the original database in
+**     rollback mode while the *-oal file is being generated.
+** 
+**     During this stage RBU does not update the database by writing
+**     directly to the target tables. Instead it creates "imposter"
+**     tables using the SQLITE_TESTCTRL_IMPOSTER interface that it uses
+**     to update each b-tree individually. All updates required by each
+**     b-tree are completed before moving on to the next, and all
+**     updates are done in sorted key order.
+** 
+**  2) The "<database>-oal" file is moved to the equivalent "<database>-wal"
+**     location using a call to rename(2). Before doing this the RBU
+**     module takes an EXCLUSIVE lock on the database file, ensuring
+**     that there are no other active readers.
+** 
+**     Once the EXCLUSIVE lock is released, any other database readers
+**     detect the new *-wal file and read the database in wal mode. At
+**     this point they see the new version of the database - including
+**     the updates made as part of the RBU update.
+** 
+**  3) The new *-wal file is checkpointed. This proceeds in the same way 
+**     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 <assert.h> */
+/* #include <string.h> */
+/* #include <stdio.h> */
+
+/* #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_<target name>" 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_<target> naming scheme. 
+**
+** Instead of the plain data_<target> naming scheme, RBU database tables 
+** may also be named data<integer>_<target>, where <integer> is any sequence
+** of zero or more numeric characters (0-9). This can be significant because
+** tables within the RBU database are always processed in order sorted by 
+** name. By judicious selection of the <integer> portion of the names
+** of the RBU tables the user can therefore control the order in which they
+** are processed. This can be useful, for example, to ensure that "external
+** content" FTS4 tables are updated before their underlying content tables.
+**
+** If the target database table is a virtual table or a table that has no
+** PRIMARY KEY declaration, the data_% table must also contain a column 
+** named "rbu_rowid". This column is mapped to the tables implicit primary 
+** key column - "rowid". Virtual tables for which the "rowid" column does 
+** not function like a primary key value cannot be updated using RBU. For 
+** 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 the index is of the following form:
+** 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.
 **
-**   CREATE INDEX i1 ON t1(c, b COLLATE nocase);
+** 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_"
 **
-** and "t1" is a table with an explicit INTEGER PRIMARY KEY column 
-** "ipk", the returned string is:
+** DATABASE LOCKING
 **
-**   "`c` COLLATE 'BINARY', `b` COLLATE 'NOCASE', `ipk` COLLATE 'BINARY'"
+** An RBU update may not be applied to a database in WAL mode. Attempting
+** to do so is an error (SQLITE_ERROR).
 **
-** As well as the returned string, three other malloc'd strings are 
-** returned via output parameters. As follows:
+** 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.
 **
-**   pzImposterCols: ...
-**   pzImposterPk: ...
-**   pzWhere: ...
+** 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).
 */
-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( i<pIter->nTblCol );
-        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++;
-  }
+#ifndef _SQLITE3RBU_H
+#define _SQLITE3RBU_H
 
-  rc2 = sqlite3_finalize(pXInfo);
-  if( rc==SQLITE_OK ) rc = rc2;
+/* #include "sqlite3.h"              ** Required for error code definitions ** */
 
-  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;
-  }
+#if 0
+extern "C" {
+#endif
 
-  *pzImposterCols = zImpCols;
-  *pzImposterPk = zImpPK;
-  *pzWhere = zWhere;
-  *pnBind = nBind;
-  return zRet;
-}
+typedef struct sqlite3rbu sqlite3rbu;
 
 /*
-** Assuming the current table columns are "a", "b" and "c", and the zObj
-** paramter is passed "old", return a string of the form:
+** Open an RBU handle.
 **
-**     "old.a, old.b, old.b"
+** 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.
 **
-** With the column names escaped.
+** 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.
 **
-** For tables with implicit rowids - RBU_PK_EXTERNAL and RBU_PK_NONE, append
-** the text ", old._rowid_" to the returned value.
+** 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.
 */
-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; i<pIter->nTblCol; 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;
-}
+SQLITE_API sqlite3rbu *sqlite3rbu_open(
+  const char *zTarget, 
+  const char *zRbu,
+  const char *zState
+);
 
 /*
-** 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:
+** 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.
 **
-**   CREATE TABLE t1(a, b, c, PRIMARY KEY(b, c));
+** 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.
 **
-** Return the string:
+** If the second argument passed to this function is NULL, then the
+** name of the state database is "<database>-vacuum", where <database>
+** is the name of the target database file. In this case, on UNIX, if the
+** state database is not already present in the file-system, it is created
+** with the same permissions as the target db is made.
 **
-**   "b = ?1 AND c = ?2"
+** 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.
 */
-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; i<pIter->nTblCol; 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; i<pIter->nTblCol; 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;
-}
+SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
+  const char *zTarget, 
+  const char *zState
+);
 
 /*
-** 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.
+** Configure a limit for the amount of temp space that may be used by
+** the RBU handle passed as the first argument. The new limit is specified
+** in bytes by the second parameter. If it is positive, the limit is updated.
+** If the second parameter to this function is passed zero, then the limit
+** is removed entirely. If the second parameter is negative, the limit is
+** not modified (this is useful for querying the current limit).
+**
+** In all cases the returned value is the current limit in bytes (zero 
+** indicates unlimited).
+**
+** If the temp space limit is exceeded during operation, an SQLITE_FULL
+** error is returned.
 */
-static void rbuBadControlError(sqlite3rbu *p){
-  p->rc = SQLITE_ERROR;
-  p->zErrmsg = sqlite3_mprintf("invalid rbu_control value");
-}
+SQLITE_API sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu*, sqlite3_int64);
 
+/*
+** Return the current amount of temp file space, in bytes, currently used by 
+** the RBU handle passed as the only argument.
+*/
+SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu*);
 
 /*
-** 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.
+** 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 memory for the returned string is obtained from sqlite3_malloc().
-** It is the responsibility of the caller to eventually free it using
-** sqlite3_free(). 
+** 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 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.
+**   * 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().
 */
-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; i<pIter->nTblCol; 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;
-}
+SQLITE_API sqlite3 *sqlite3rbu_db(sqlite3rbu*, int bRbu);
 
 /*
-** 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 "?,?,?".
+** Do some work towards applying the RBU update to the target db. 
 **
-** 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(). 
+** 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. 
 **
-** 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.
+** 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.
 */
-static char *rbuObjIterGetBindlist(sqlite3rbu *p, int nBind){
-  char *zRet = 0;
-  int nByte = nBind*2 + 1;
+SQLITE_API int sqlite3rbu_step(sqlite3rbu *pRbu);
 
-  zRet = (char*)rbuMalloc(p, nByte);
-  if( zRet ){
-    int i;
-    for(i=0; i<nBind; i++){
-      zRet[i*2] = '?';
-      zRet[i*2+1] = (i+1==nBind) ? '\0' : ',';
-    }
-  }
-  return zRet;
-}
+/*
+** 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);
 
 /*
-** The iterator currently points to a table (not index) of type 
-** RBU_PK_WITHOUT_ROWID. This function creates the PRIMARY KEY 
-** declaration for the corresponding imposter table. For example,
-** if the iterator points to a table created as:
+** Close an RBU handle. 
 **
-**   CREATE TABLE t1(a, b, c, PRIMARY KEY(b, a DESC)) WITHOUT ROWID
+** 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.
 **
-** this function returns:
+** 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, if pzErrmsg is not NULL,
+** *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().
 **
-**   PRIMARY KEY("b", "a" DESC)
+** 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.
 */
-static char *rbuWithoutRowidPK(sqlite3rbu *p, RbuObjIter *pIter){
-  char *z = 0;
-  assert( pIter->zIdx==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 = <pk-index> */
-   
-    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);
+SQLITE_API int sqlite3rbu_close(sqlite3rbu *pRbu, char **pzErrmsg);
 
-    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;
-}
+/*
+** 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);
 
 /*
-** 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. 
+** 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.
 **
-** 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:
+** An RBU update is divided into two stages:
 **
-**   CREATE TABLE t1(a, b TEXT, c REAL, PRIMARY KEY(b, c));
+**   * 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.
 **
-** then the imposter table schema is:
+** The update is visible to non-RBU clients during stage 2. During stage 1
+** non-RBU reader clients may see the original database.
 **
-**   CREATE TABLE rbu_imposter2(c1 TEXT, c2 REAL, id INTEGER) WITHOUT ROWID;
+** 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.
 **
-*/
-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 %Q", 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.
+** 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:
 **
-** 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.
+**   CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID;
 **
-** 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.
+** 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.
 */
-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 && iCol<pIter->nTblCol; 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 %Q%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);
-  }
-}
+SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int*pnTwo);
 
 /*
-** Prepare a statement used to insert rows into the "rbu_tmp_xxx" table.
-** Specifically a statement of the form:
+** 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:
 **
-**     INSERT INTO rbu_tmp_xxx VALUES(?, ?, ? ...);
+** 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.
 **
-** 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 && i<nVal; i++){
-    rc = sqlite3_bind_value(p->objiter.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.
+** 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.
 */
-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
-            )
-        );
-      }
+#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
 
-      sqlite3_free(zWhere);
-      sqlite3_free(zOldlist);
-      sqlite3_free(zNewlist);
-      sqlite3_free(zBindings);
-    }
-    sqlite3_free(zCollist);
-    sqlite3_free(zLimit);
-  }
-  
-  return p->rc;
-}
+SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu);
 
 /*
-** 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);
-  }
+** 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);
 
-  if( pUp ){
-    char *zWhere = rbuObjIterGetWhere(p, pIter);
-    char *zSet = rbuObjIterGetSetlist(p, pIter, zMask);
-    char *zUpdate = 0;
+/*
+** 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);
 
-    pUp->zMask = (char*)&pUp[1];
-    memcpy(pUp->zMask, zMask, pIter->nTblCol);
-    pUp->pNext = pIter->pRbuUpdate;
-    pIter->pRbuUpdate = pUp;
+#if 0
+}  /* end of the 'extern "C"' block */
+#endif
 
-    if( zSet ){
-      const char *zPrefix = "";
+#endif /* _SQLITE3RBU_H */
 
-      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);
-  }
+/************** End of sqlite3rbu.h ******************************************/
+/************** Continuing where we left off in sqlite3rbu.c *****************/
 
-  return p->rc;
-}
+#if defined(_WIN32_WCE)
+/* #include "windows.h" */
+#endif
 
-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;
-}
+/* Maximum number of prepared UPDATE statements held by this module */
+#define SQLITE_RBU_UPDATE_CACHESIZE 16
+
+/* Delta checksums disabled by default.  Compile with -DRBU_ENABLE_DELTA_CKSUM
+** to enable checksum verification.
+*/
+#ifndef RBU_ENABLE_DELTA_CKSUM
+# define RBU_ENABLE_DELTA_CKSUM 0
+#endif
 
 /*
-** Free an RbuState object allocated by rbuLoadState().
+** Swap two objects of type TYPE.
 */
-static void rbuFreeState(RbuState *p){
-  if( p ){
-    sqlite3_free(p->zTbl);
-    sqlite3_free(p->zDataTbl);
-    sqlite3_free(p->zIdx);
-    sqlite3_free(p);
-  }
-}
+#if !defined(SQLITE_AMALGAMATION)
+# define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;}
+#endif
 
 /*
-** 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().
+** 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:
 **
-** If an error occurs, leave an error code and message in the rbu handle
-** and return NULL.
+** 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.
+**
+** RBU_STATE_DATATBL:
+**   Only valid if STAGE==1. The RBU database name of the table 
+**   currently being read.
 */
-static RbuState *rbuLoadState(sqlite3rbu *p){
-  RbuState *pRet = 0;
-  sqlite3_stmt *pStmt = 0;
-  int rc;
-  int rc2;
+#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_STATE_DATATBL     10
 
-  pRet = (RbuState*)rbuMalloc(p, sizeof(RbuState));
-  if( pRet==0 ) return 0;
+#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
 
-  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;
+#define RBU_CREATE_STATE \
+  "CREATE TABLE IF NOT EXISTS %s.rbu_state(k INTEGER PRIMARY KEY, v)"
 
-      case RBU_STATE_IDX:
-        pRet->zIdx = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
-        break;
+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;
 
-      case RBU_STATE_ROW:
-        pRet->nRow = sqlite3_column_int(pStmt, 1);
-        break;
+#if !defined(SQLITE_AMALGAMATION)
+typedef unsigned int u32;
+typedef unsigned short u16;
+typedef unsigned char u8;
+typedef sqlite3_int64 i64;
+#endif
 
-      case RBU_STATE_PROGRESS:
-        pRet->nProgress = sqlite3_column_int64(pStmt, 1);
-        break;
+/*
+** 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
 
-      case RBU_STATE_CKPT:
-        pRet->iWalCksum = sqlite3_column_int64(pStmt, 1);
-        break;
+#define SQLITE_FCNTL_RBUCNT    5149216
 
-      case RBU_STATE_COOKIE:
-        pRet->iCookie = (u32)sqlite3_column_int64(pStmt, 1);
-        break;
+/*
+** A structure to store values read from the rbu_state table in memory.
+*/
+struct RbuState {
+  int eStage;
+  char *zTbl;
+  char *zDataTbl;
+  char *zIdx;
+  i64 iWalCksum;
+  int nRow;
+  i64 nProgress;
+  u32 iCookie;
+  i64 iOalSz;
+  i64 nPhaseOneStep;
+};
 
-      case RBU_STATE_OALSZ:
-        pRet->iOalSz = (u32)sqlite3_column_int64(pStmt, 1);
-        break;
+struct RbuUpdateStmt {
+  char *zMask;                    /* Copy of update mask used with pUpdate */
+  sqlite3_stmt *pUpdate;          /* Last update statement (or NULL) */
+  RbuUpdateStmt *pNext;
+};
 
-      case RBU_STATE_PHASEONESTEP:
-        pRet->nPhaseOneStep = sqlite3_column_int64(pStmt, 1);
-        break;
+/*
+** 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 */
 
-      case RBU_STATE_DATATBL:
-        pRet->zDataTbl = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
-        break;
+  /* 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 */
 
-      default:
-        rc = SQLITE_CORRUPT;
-        break;
-    }
-  }
-  rc2 = sqlite3_finalize(pStmt);
-  if( rc==SQLITE_OK ) rc = rc2;
+  /* 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 */
 
-  p->rc = rc;
-  return pRet;
-}
+  /* 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
 
 
 /*
-** 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.
+** Within the RBU_STAGE_OAL stage, each call to sqlite3rbu_step() performs
+** one of the following operations.
 */
-static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
-  assert( p->rc || (p->dbMain==0 && p->dbRbu==0) );
-  assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 );
+#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 */
 
-  /* Open the RBU database */
-  p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1);
+#define RBU_UPDATE     6          /* Update a row in a main table b-tree */
 
-  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);
-    }
-  }
+/*
+** 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;
+};
 
-  /* 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);
-  }
+/*
+** 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;
 
-#if 0
-  if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){
-    p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, 0);
-  }
-#endif
+  /* 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;
+  i64 szTemp;                     /* Current size of all temp files in use */
+  i64 szTempLimit;                /* Total size limit for temp files */
 
-  /* If it has not already been created, create the rbu_state table */
-  rbuMPrintfExec(p, p->dbRbu, RBU_CREATE_STATE, p->zStateDb);
+  /* Used in RBU vacuum mode only */
+  int nRbu;                       /* Number of RBU VFS in the stack */
+  rbu_file *pRbuFd;               /* Fd for main db of dbRbu */
+};
 
-#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;
+/*
+** An rbu VFS is implemented using an instance of this structure.
+**
+** Variable pRbu is only non-NULL for automatically created RBU VFS objects.
+** It is NULL for RBU VFS objects created explicitly using
+** sqlite3rbu_create_vfs(). It is used to track the total amount of temp
+** space used by the RBU handle.
+*/
+struct rbu_vfs {
+  sqlite3_vfs base;               /* rbu VFS shim methods */
+  sqlite3_vfs *pRealVfs;          /* Underlying VFS */
+  sqlite3_mutex *mutex;           /* Mutex to protect pMain */
+  sqlite3rbu *pRbu;               /* Owner RBU object */
+  rbu_file *pMain;                /* Linked list of main db files */
+};
 
-      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
+/*
+** Each file opened by an rbu VFS is represented by an instance of
+** the following structure.
+**
+** If this is a temporary file (pRbu!=0 && flags&DELETE_ON_CLOSE), variable
+** "sz" is set to the current size of the database file.
+*/
+struct rbu_file {
+  sqlite3_file base;              /* sqlite3_file methods */
+  sqlite3_file *pReal;            /* Underlying file handle */
+  rbu_vfs *pRbuVfs;               /* Pointer to the rbu_vfs object */
+  sqlite3rbu *pRbu;               /* Pointer to rbu object (rbu target only) */
+  i64 sz;                         /* Size of file in bytes (temp only) */
 
-  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);
-  }
+  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 */
 
-  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;
-      }
+  int nShm;                       /* Number of entries in apShm[] array */
+  char **apShm;                   /* Array of mmap'd *-shm regions */
+  char *zDel;                     /* Delete this when closing file */
 
-      zTarget = sqlite3_mprintf("file:%s-vacuum?rbu_memory=1%s%s", 
-          sqlite3_db_filename(p->dbRbu, "main"),
-          (zExtra==0 ? "" : "&"), (zExtra==0 ? "" : zExtra)
-      );
+  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 */
+};
 
-      if( zTarget==0 ){
-        p->rc = SQLITE_NOMEM;
-        return;
-      }
-      p->dbMain = rbuOpenDbhandle(p, zTarget, p->nRbu<=1);
-      sqlite3_free(zTarget);
-    }
-  }
+/*
+** True for an RBU vacuum handle, or false otherwise.
+*/
+#define rbuIsVacuum(p) ((p)->zTarget==0)
 
-  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
-    );
-  }
+/*************************************************************************
+** 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().
+*/
 
-  if( p->rc==SQLITE_OK ){
-    p->rc = sqlite3_create_function(p->dbRbu, 
-        "rbu_target_name", -1, SQLITE_UTF8, (void*)p, rbuTargetNameFunc, 0, 0
-    );
+/*
+** 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;
+}
 
-  if( p->rc==SQLITE_OK ){
-    p->rc = sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_RBU, (void*)p);
+#if RBU_ENABLE_DELTA_CKSUM
+/*
+** 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;
   }
-  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);
+  while(N >= 4){
+    sum0 += z[0];
+    sum1 += z[1];
+    sum2 += z[2];
+    sum3 += z[3];
+    z += 4;
+    N -= 4;
   }
-
-  if( p->rc==SQLITE_NOTFOUND ){
-    p->rc = SQLITE_ERROR;
-    p->zErrmsg = sqlite3_mprintf("rbu vfs not found");
+  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;
 }
+#endif
 
 /*
-** 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.
+** Apply a delta.
 **
-** 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.
+** 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.
 **
-** If SQLITE_ENABLE_8_3_NAMES is set to 2 at compile-time, then always
-** do the suffix shortening regardless of URI parameter.
+** 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.
 **
-** Examples:
+** 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.
 **
-**     test.db-journal    =>   test.nal
-**     test.db-wal        =>   test.wal
-**     test.db-shm        =>   test.shm
-**     test.db-mj7f3319fa =>   test.9fa
+** Refer to the delta_create() documentation above for a description
+** of the delta file format.
 */
-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) )
+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;
+#if RBU_ENABLE_DELTA_CKSUM
+  char *zOrigOut = zOut;
 #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);
+
+  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;
+#if RBU_ENABLE_DELTA_CKSUM
+        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;
 }
 
-/*
-** 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];
-    }
+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 iRet;
+  return size;
 }
 
 /*
-** 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.
+** End of code taken from fossil.
+*************************************************************************/
+
+/*
+** Implementation of SQL scalar function rbu_fossil_delta().
 **
-** 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.
+** 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 rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){
+static void rbuFossilDeltaFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  const char *aDelta;
+  int nDelta;
+  const char *aOrig;
+  int nOrig;
 
-  /* 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);
-    }
-  }
+  int nOut;
+  int nOut2;
+  char *aOut;
 
-  /* 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;
-  }
+  assert( argc==2 );
 
-  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);
+  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;
   }
 
-  if( p->rc==SQLITE_OK ){
-    if( p->nFrame==0 || (pState && pState->iWalCksum!=p->iWalCksum) ){
-      p->rc = SQLITE_DONE;
-      p->eStage = RBU_STAGE_DONE;
+  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{
-      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);
+      sqlite3_result_blob(context, aOut, nOut, sqlite3_free);
     }
   }
 }
 
+
 /*
-** 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.
+** 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 rbuCaptureWalRead(sqlite3rbu *pRbu, i64 iOff, int iAmt){
-  const u32 mReq = (1<<WAL_LOCK_WRITE)|(1<<WAL_LOCK_CKPT)|(1<<WAL_LOCK_READ0);
-  u32 iFrame;
-
-  if( pRbu->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;
+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;
   }
-
-  iFrame = (u32)((iOff-32) / (i64)(iAmt+24)) + 1;
-  if( pRbu->iMaxFrame<iFrame ) pRbu->iMaxFrame = iFrame;
-  pRbu->aFrame[pRbu->nFrame].iWalFrame = iFrame;
-  pRbu->aFrame[pRbu->nFrame].iDbPage = 0;
-  pRbu->nFrame++;
-  return SQLITE_OK;
+  return rc;
 }
 
 /*
-** Called when a page of data is written to offset iOff of the database
-** file while the rbu handle is in capture mode. Record the page number 
-** of the page being written in the aFrame[] array.
+** 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 rbuCaptureDbWrite(sqlite3rbu *pRbu, i64 iOff){
-  pRbu->aFrame[pRbu->nFrame-1].iDbPage = (u32)(iOff / pRbu->pgsz) + 1;
-  return SQLITE_OK;
+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;
 }
 
 /*
-** This is called as part of an incremental checkpoint operation. Copy
-** a single frame of data from the wal file into the database file, as
-** indicated by the RbuFrame object.
+** 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 void rbuCheckpointFrame(sqlite3rbu *p, RbuFrame *pFrame){
-  sqlite3_file *pWal = p->pTargetFd->pWalFd->pReal;
-  sqlite3_file *pDb = p->pTargetFd->pReal;
-  i64 iOff;
-
-  assert( p->rc==SQLITE_OK );
-  iOff = (i64)(pFrame->iWalFrame-1) * (p->pgsz + 24) + 32 + 24;
-  p->rc = pWal->pMethods->xRead(pWal, p->aBuf, p->pgsz, iOff);
-  if( p->rc ) return;
-
-  iOff = (i64)(pFrame->iDbPage-1) * p->pgsz;
-  p->rc = pDb->pMethods->xWrite(pDb, p->aBuf, p->pgsz, iOff);
+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;
 }
 
-
 /*
-** Take an EXCLUSIVE lock on the database file.
+** Free the RbuObjIter.azTblCol[] and RbuObjIter.abTblPk[] arrays allocated
+** by an earlier call to rbuObjIterCacheTableInfo().
 */
-static void rbuLockDatabase(sqlite3rbu *p){
-  sqlite3_file *pReal = p->pTargetFd->pReal;
-  assert( p->rc==SQLITE_OK );
-  p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_SHARED);
-  if( p->rc==SQLITE_OK ){
-    p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_EXCLUSIVE);
+static void rbuObjIterFreeCols(RbuObjIter *pIter){
+  int i;
+  for(i=0; i<pIter->nTblCol; 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 */
 }
 
-#if defined(_WIN32_WCE)
-static LPWSTR rbuWinUtf8ToUnicode(const char *zFilename){
-  int nChar;
-  LPWSTR zWideFilename;
+/*
+** Finalize all statements and free all allocations that are specific to
+** the current object (table/index pair).
+*/
+static void rbuObjIterClearStatements(RbuObjIter *pIter){
+  RbuUpdateStmt *pUp;
 
-  nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
-  if( nChar==0 ){
-    return 0;
-  }
-  zWideFilename = sqlite3_malloc64( nChar*sizeof(zWideFilename[0]) );
-  if( zWideFilename==0 ){
-    return 0;
-  }
-  memset(zWideFilename, 0, nChar*sizeof(zWideFilename[0]));
-  nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename,
-                                nChar);
-  if( nChar==0 ){
-    sqlite3_free(zWideFilename);
-    zWideFilename = 0;
+  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;
   }
-  return zWideFilename;
+  
+  pIter->pSelect = 0;
+  pIter->pInsert = 0;
+  pIter->pDelete = 0;
+  pIter->pRbuUpdate = 0;
+  pIter->pTmpInsert = 0;
+  pIter->nCol = 0;
 }
-#endif
 
 /*
-** The RBU handle is currently in RBU_STAGE_OAL state, with a SHARED lock
-** on the database file. This proc moves the *-oal file to the *-wal path,
-** then reopens the database file (this time in vanilla, non-oal, WAL mode).
-** If an error occurs, leave an error code and error message in the rbu 
-** handle.
+** Clean up any resources allocated as part of the iterator object passed
+** as the only argument.
 */
-static void rbuMoveOalFile(sqlite3rbu *p){
-  const char *zBase = sqlite3_db_filename(p->dbMain, "main");
-  const char *zMove = zBase;
-  char *zOal;
-  char *zWal;
-
-  if( rbuIsVacuum(p) ){
-    zMove = sqlite3_db_filename(p->dbRbu, "main");
-  }
-  zOal = sqlite3_mprintf("%s-oal", zMove);
-  zWal = sqlite3_mprintf("%s-wal", zMove);
-
-  assert( p->eStage==RBU_STAGE_MOVE );
-  assert( p->rc==SQLITE_OK && p->zErrmsg==0 );
-  if( zWal==0 || zOal==0 ){
-    p->rc = SQLITE_NOMEM;
-  }else{
-    /* Move the *-oal file to *-wal. At this point connection p->db is
-    ** holding a SHARED lock on the target database file (because it is
-    ** in WAL mode). So no other connection may be writing the db. 
-    **
-    ** In order to ensure that there are no database readers, an EXCLUSIVE
-    ** lock is obtained here before the *-oal is moved to *-wal.
-    */
-    rbuLockDatabase(p);
-    if( p->rc==SQLITE_OK ){
-      rbuFileSuffix3(zBase, zWal);
-      rbuFileSuffix3(zBase, zOal);
+static void rbuObjIterFinalize(RbuObjIter *pIter){
+  rbuObjIterClearStatements(pIter);
+  sqlite3_finalize(pIter->pTblIter);
+  sqlite3_finalize(pIter->pIdxIter);
+  rbuObjIterFreeCols(pIter);
+  memset(pIter, 0, sizeof(RbuObjIter));
+}
 
-      /* Re-open the databases. */
-      rbuObjIterFinalize(&p->objiter);
-      sqlite3_close(p->dbRbu);
-      sqlite3_close(p->dbMain);
-      p->dbMain = 0;
-      p->dbRbu = 0;
+/*
+** 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 ){
 
-#if defined(_WIN32_WCE)
-      {
-        LPWSTR zWideOal;
-        LPWSTR zWideWal;
+    /* 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
+      );
+    }
 
-        zWideOal = rbuWinUtf8ToUnicode(zOal);
-        if( zWideOal ){
-          zWideWal = rbuWinUtf8ToUnicode(zWal);
-          if( zWideWal ){
-            if( MoveFileW(zWideOal, zWideWal) ){
-              p->rc = SQLITE_OK;
-            }else{
-              p->rc = SQLITE_IOERR;
-            }
-            sqlite3_free(zWideWal);
+    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{
-            p->rc = SQLITE_IOERR_NOMEM;
+            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;
           }
-          sqlite3_free(zWideOal);
-        }else{
-          p->rc = SQLITE_IOERR_NOMEM;
         }
       }
-#else
-      p->rc = rename(zOal, zWal) ? SQLITE_IOERR : SQLITE_OK;
-#endif
-
-      if( p->rc==SQLITE_OK ){
-        rbuOpenDatabase(p, 0);
-        rbuSetupCheckpoint(p, 0);
-      }
     }
   }
 
-  sqlite3_free(zWal);
-  sqlite3_free(zOal);
+  if( rc!=SQLITE_OK ){
+    rbuObjIterFinalize(pIter);
+    p->rc = rc;
+  }
+  return rc;
 }
 
+
 /*
-** The SELECT statement iterating through the keys for the current object
-** (p->objiter.pSelect) currently points to a valid row. This function
-** determines the type of operation requested by this row and returns
-** one of the following values to indicate the result:
+** 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. 
 **
-**     * RBU_INSERT
-**     * RBU_DELETE
-**     * RBU_IDX_DELETE
-**     * RBU_UPDATE
+** For a non-vacuum RBU handle, if the table name matches the pattern:
 **
-** If RBU_UPDATE is returned, then output variable *pzMask is set to
-** point to the text value indicating the columns to update.
+**     data[0-9]_<name>
 **
-** If the rbu_control field contains an invalid value, an error code and
-** message are left in the RBU handle and zero returned.
+** where <name> is any sequence of 1 or more characters, <name> 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 int rbuStepType(sqlite3rbu *p, const char **pzMask){
-  int iCol = p->objiter.nCol;     /* Index of rbu_control column */
-  int res = 0;                    /* Return value */
+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 );
 
-  switch( sqlite3_column_type(p->objiter.pSelect, iCol) ){
-    case SQLITE_INTEGER: {
-      int iVal = sqlite3_column_int(p->objiter.pSelect, iCol);
-      switch( iVal ){
-        case 0: res = RBU_INSERT;     break;
-        case 1: res = RBU_DELETE;     break;
-        case 2: res = RBU_REPLACE;    break;
-        case 3: res = RBU_IDX_DELETE; break;
-        case 4: res = RBU_IDX_INSERT; break;
+  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);
       }
-      break;
-    }
-
-    case SQLITE_TEXT: {
-      const unsigned char *z = sqlite3_column_text(p->objiter.pSelect, iCol);
-      if( z==0 ){
-        p->rc = SQLITE_NOMEM;
-      }else{
-        *pzMask = (const char*)z;
+    }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);
+        }
       }
-      res = RBU_UPDATE;
-
-      break;
     }
-
-    default:
-      break;
-  }
-
-  if( res==0 ){
-    rbuBadControlError(p);
   }
-  return res;
-}
-
-#ifdef SQLITE_DEBUG
-/*
-** Assert that column iCol of statement pStmt is named zName.
-*/
-static void assertColumnName(sqlite3_stmt *pStmt, int iCol, const char *zName){
-  const char *zCol = sqlite3_column_name(pStmt, iCol);
-  assert( 0==sqlite3_stricmp(zName, zCol) );
 }
-#else
-# define assertColumnName(x,y,z)
-#endif
 
 /*
-** Argument eType must be one of RBU_INSERT, RBU_DELETE, RBU_IDX_INSERT or
-** RBU_IDX_DELETE. This function performs the work of a single
-** sqlite3rbu_step() call for the type of operation specified by eType.
+** 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 void rbuStepOneOp(sqlite3rbu *p, int eType){
-  RbuObjIter *pIter = &p->objiter;
-  sqlite3_value *pVal;
-  sqlite3_stmt *pWriter;
-  int i;
-
-  assert( p->rc==SQLITE_OK );
-  assert( eType!=RBU_DELETE || pIter->zIdx==0 );
-  assert( eType==RBU_DELETE || eType==RBU_IDX_DELETE
-       || eType==RBU_INSERT || eType==RBU_IDX_INSERT
-  );
+static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){
+  int rc;
+  memset(pIter, 0, sizeof(RbuObjIter));
 
-  /* If this is a delete, decrement nPhaseOneStep by nIndex. If the DELETE
-  ** statement below does actually delete a row, nPhaseOneStep will be
-  ** incremented by the same amount when SQL function rbu_tmp_insert()
-  ** is invoked by the trigger.  */
-  if( eType==RBU_DELETE ){
-    p->nPhaseOneStep -= p->objiter.nIndex;
-  }
+  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( eType==RBU_IDX_DELETE || eType==RBU_DELETE ){
-    pWriter = pIter->pDelete;
-  }else{
-    pWriter = pIter->pInsert;
+  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 = ?"
+    );
   }
 
-  for(i=0; i<pIter->nCol; i++){
-    /* If this is an INSERT into a table b-tree and the table has an
-    ** explicit INTEGER PRIMARY KEY, check that this is not an attempt
-    ** to write a NULL into the IPK column. That is not permitted.  */
-    if( eType==RBU_INSERT 
-     && pIter->zIdx==0 && pIter->eType==RBU_PK_IPK && pIter->abTblPk[i] 
-     && sqlite3_column_type(pIter->pSelect, i)==SQLITE_NULL
-    ){
-      p->rc = SQLITE_MISMATCH;
-      p->zErrmsg = sqlite3_mprintf("datatype mismatch");
-      return;
-    }
-
-    if( eType==RBU_DELETE && pIter->abTblPk[i]==0 ){
-      continue;
-    }
+  pIter->bCleanup = 1;
+  p->rc = rc;
+  return rbuObjIterNext(p, pIter);
+}
 
-    pVal = sqlite3_column_value(pIter->pSelect, i);
-    p->rc = sqlite3_bind_value(pWriter, i+1, pVal);
-    if( p->rc ) return;
-  }
-  if( pIter->zIdx==0 ){
-    if( pIter->eType==RBU_PK_VTAB 
-     || pIter->eType==RBU_PK_NONE 
-     || (pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p)) 
-    ){
-      /* For a virtual table, or a table with no primary key, the 
-      ** SELECT statement is:
-      **
-      **   SELECT <cols>, rbu_control, rbu_rowid FROM ....
-      **
-      ** Hence column_value(pIter->nCol+1).
-      */
-      assertColumnName(pIter->pSelect, pIter->nCol+1, 
-          rbuIsVacuum(p) ? "rowid" : "rbu_rowid"
-      );
-      pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
-      p->rc = sqlite3_bind_value(pWriter, pIter->nCol+1, pVal);
-    }
-  }
+/*
+** 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 ){
-    sqlite3_step(pWriter);
-    p->rc = resetAndCollectError(pWriter, &p->zErrmsg);
+    if( zSql==0 ) p->rc = SQLITE_NOMEM;
+  }else{
+    sqlite3_free(zSql);
+    zSql = 0;
   }
+  va_end(ap);
+  return zSql;
 }
 
 /*
-** This function does the work for an sqlite3rbu_step() call.
-**
-** The object-iterator (p->objiter) currently points to a valid object,
-** and the input cursor (p->objiter.pSelect) currently points to a valid
-** input row. Perform whatever processing is required and return.
+** 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 no  error occurs, SQLITE_OK is returned. Otherwise, an error code
-** and message is left in the RBU handle and a copy of the error code
-** returned.
+** 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 rbuStep(sqlite3rbu *p){
-  RbuObjIter *pIter = &p->objiter;
-  const char *zMask = 0;
-  int eType = rbuStepType(p, &zMask);
-
-  if( eType ){
-    assert( eType==RBU_INSERT     || eType==RBU_DELETE
-         || eType==RBU_REPLACE    || eType==RBU_IDX_DELETE
-         || eType==RBU_IDX_INSERT || eType==RBU_UPDATE
-    );
-    assert( eType!=RBU_UPDATE || pIter->zIdx==0 );
-
-    if( pIter->zIdx==0 && (eType==RBU_IDX_DELETE || eType==RBU_IDX_INSERT) ){
-      rbuBadControlError(p);
-    }
-    else if( eType==RBU_REPLACE ){
-      if( pIter->zIdx==0 ){
-        p->nPhaseOneStep += p->objiter.nIndex;
-        rbuStepOneOp(p, RBU_DELETE);
-      }
-      if( p->rc==SQLITE_OK ) rbuStepOneOp(p, RBU_INSERT);
-    }
-    else if( eType!=RBU_UPDATE ){
-      rbuStepOneOp(p, eType);
-    }
-    else{
-      sqlite3_value *pVal;
-      sqlite3_stmt *pUpdate = 0;
-      assert( eType==RBU_UPDATE );
-      p->nPhaseOneStep -= p->objiter.nIndex;
-      rbuGetUpdateStmt(p, pIter, zMask, &pUpdate);
-      if( pUpdate ){
-        int i;
-        for(i=0; p->rc==SQLITE_OK && i<pIter->nCol; i++){
-          char c = zMask[pIter->aiSrcOrder[i]];
-          pVal = sqlite3_column_value(pIter->pSelect, i);
-          if( pIter->abTblPk[i] || c!='.' ){
-            p->rc = sqlite3_bind_value(pUpdate, i+1, pVal);
-          }
-        }
-        if( p->rc==SQLITE_OK 
-         && (pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE) 
-        ){
-          /* Bind the rbu_rowid value to column _rowid_ */
-          assertColumnName(pIter->pSelect, pIter->nCol+1, "rbu_rowid");
-          pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
-          p->rc = sqlite3_bind_value(pUpdate, pIter->nCol+1, pVal);
-        }
-        if( p->rc==SQLITE_OK ){
-          sqlite3_step(pUpdate);
-          p->rc = resetAndCollectError(pUpdate, &p->zErrmsg);
-        }
-      }
+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;
 }
 
 /*
-** Increment the schema cookie of the main database opened by p->dbMain.
+** Attempt to allocate and return a pointer to a zeroed block of nByte 
+** bytes. 
 **
-** Or, if this is an RBU vacuum, set the schema cookie of the main db
-** opened by p->dbMain to one more than the schema cookie of the main
-** db opened by p->dbRbu.
+** 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 rbuIncrSchemaCookie(sqlite3rbu *p){
+static void *rbuMalloc(sqlite3rbu *p, int nByte){
+  void *pRet = 0;
   if( p->rc==SQLITE_OK ){
-    sqlite3 *dbread = (rbuIsVacuum(p) ? p->dbRbu : p->dbMain);
-    int iCookie = 1000000;
-    sqlite3_stmt *pStmt;
-
-    p->rc = prepareAndCollectError(dbread, &pStmt, &p->zErrmsg, 
-        "PRAGMA schema_version"
-    );
-    if( p->rc==SQLITE_OK ){
-      /* Coverage: it may be that this sqlite3_step() cannot fail. There
-      ** is already a transaction open, so the prepared statement cannot
-      ** throw an SQLITE_SCHEMA exception. The only database page the
-      ** statement reads is page 1, which is guaranteed to be in the cache.
-      ** And no memory allocations are required.  */
-      if( SQLITE_ROW==sqlite3_step(pStmt) ){
-        iCookie = sqlite3_column_int(pStmt, 0);
-      }
-      rbuFinalize(p, pStmt);
-    }
-    if( p->rc==SQLITE_OK ){
-      rbuMPrintfExec(p, p->dbMain, "PRAGMA schema_version = %d", iCookie+1);
+    assert( nByte>0 );
+    pRet = sqlite3_malloc64(nByte);
+    if( pRet==0 ){
+      p->rc = SQLITE_NOMEM;
+    }else{
+      memset(pRet, 0, nByte);
     }
   }
+  return pRet;
 }
 
+
 /*
-** Update the contents of the rbu_state table within the rbu database. The
-** value stored in the RBU_STATE_STAGE column is eStage. All other values
-** are determined by inspecting the rbu handle passed as the first argument.
+** 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 rbuSaveState(sqlite3rbu *p, int eStage){
-  if( p->rc==SQLITE_OK || p->rc==SQLITE_DONE ){
-    sqlite3_stmt *pInsert = 0;
-    rbu_file *pFd = (rbuIsVacuum(p) ? p->pRbuFd : p->pTargetFd);
-    int rc;
+static void rbuAllocateIterArrays(sqlite3rbu *p, RbuObjIter *pIter, int nCol){
+  int nByte = (2*sizeof(char*) + sizeof(int) + 3*sizeof(u8)) * nCol;
+  char **azNew;
 
-    assert( p->zErrmsg==0 );
-    rc = prepareFreeAndCollectError(p->dbRbu, &pInsert, &p->zErrmsg, 
-        sqlite3_mprintf(
-          "INSERT OR REPLACE INTO %s.rbu_state(k, v) VALUES "
-          "(%d, %d), "
-          "(%d, %Q), "
-          "(%d, %Q), "
-          "(%d, %d), "
-          "(%d, %d), "
-          "(%d, %lld), "
-          "(%d, %lld), "
-          "(%d, %lld), "
-          "(%d, %lld), "
-          "(%d, %Q)  ",
-          p->zStateDb,
-          RBU_STATE_STAGE, eStage,
-          RBU_STATE_TBL, p->objiter.zTbl, 
-          RBU_STATE_IDX, p->objiter.zIdx, 
-          RBU_STATE_ROW, p->nStep, 
-          RBU_STATE_PROGRESS, p->nProgress,
-          RBU_STATE_CKPT, p->iWalCksum,
-          RBU_STATE_COOKIE, (i64)pFd->iCookie,
-          RBU_STATE_OALSZ, p->iOalSz,
-          RBU_STATE_PHASEONESTEP, p->nPhaseOneStep,
-          RBU_STATE_DATATBL, p->objiter.zDataTbl
-      )
-    );
-    assert( pInsert==0 || rc==SQLITE_OK );
+  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];
+  }
+}
 
-    if( rc==SQLITE_OK ){
-      sqlite3_step(pInsert);
-      rc = sqlite3_finalize(pInsert);
+/*
+** 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;
     }
-    if( rc!=SQLITE_OK ) p->rc = rc;
   }
-}
 
+  return zRet;
+}
 
 /*
-** The second argument passed to this function is the name of a PRAGMA 
-** setting - "page_size", "auto_vacuum", "user_version" or "application_id".
-** This function executes the following on sqlite3rbu.dbRbu:
+** Finalize the statement passed as the second argument.
 **
-**   "PRAGMA main.$zPragma"
+** 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.
 **
-** where $zPragma is the string passed as the second argument, then
-** on sqlite3rbu.dbMain:
+**   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.
 **
-**   "PRAGMA main.$zPragma = $val"
+**     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.
 **
-** where $val is the value returned by the first PRAGMA invocation.
+**   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.
 **
-** In short, it copies the value  of the specified PRAGMA setting from
-** dbRbu to dbMain.
+** 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 rbuCopyPragma(sqlite3rbu *p, const char *zPragma){
-  if( p->rc==SQLITE_OK ){
-    sqlite3_stmt *pPragma = 0;
-    p->rc = prepareFreeAndCollectError(p->dbRbu, &pPragma, &p->zErrmsg, 
-        sqlite3_mprintf("PRAGMA main.%s", zPragma)
-    );
-    if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPragma) ){
-      p->rc = rbuMPrintfExec(p, p->dbMain, "PRAGMA main.%s = %d",
-          zPragma, sqlite3_column_int(pPragma, 0)
-      );
-    }
-    rbuFinalize(p, pPragma);
-  }
-}
+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};
 
-/*
-** The RBU handle passed as the only argument has just been opened and 
-** the state database is empty. If this RBU handle was opened for an
-** RBU vacuum operation, create the schema in the target db.
-*/
-static void rbuCreateTargetSchema(sqlite3rbu *p){
-  sqlite3_stmt *pSql = 0;
-  sqlite3_stmt *pInsert = 0;
+  *peType = RBU_PK_NOTABLE;
+  *piPk = 0;
 
-  assert( rbuIsVacuum(p) );
-  p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=1", 0,0, &p->zErrmsg);
-  if( p->rc==SQLITE_OK ){
-    p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg, 
-      "SELECT sql FROM sqlite_master WHERE sql!='' AND rootpage!=0"
-      " AND name!='sqlite_sequence' "
-      " ORDER BY type DESC"
-    );
+  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);
 
-  while( p->rc==SQLITE_OK && sqlite3_step(pSql)==SQLITE_ROW ){
-    const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
-    p->rc = sqlite3_exec(p->dbMain, zSql, 0, 0, &p->zErrmsg);
+  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;
+    }
   }
-  rbuFinalize(p, pSql);
-  if( p->rc!=SQLITE_OK ) return;
 
+  p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[3], &p->zErrmsg, 
+    sqlite3_mprintf("PRAGMA table_info=%Q",zTab)
+  );
   if( p->rc==SQLITE_OK ){
-    p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg, 
-        "SELECT * FROM sqlite_master WHERE rootpage=0 OR rootpage IS NULL" 
-    );
+    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; i<sizeof(aStmt)/sizeof(aStmt[0]); i++){
+      rbuFinalize(p, aStmt[i]);
+    }
   }
+}
+
+/*
+** This is a helper function for rbuObjIterCacheTableInfo(). It populates
+** the pIter->abIndexed[] array.
+*/
+static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){
+  sqlite3_stmt *pList = 0;
+  int bIndex = 0;
 
   if( p->rc==SQLITE_OK ){
-    p->rc = prepareAndCollectError(p->dbMain, &pInsert, &p->zErrmsg, 
-        "INSERT INTO sqlite_master VALUES(?,?,?,?,?)"
+    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)
     );
   }
 
-  while( p->rc==SQLITE_OK && sqlite3_step(pSql)==SQLITE_ROW ){
-    int i;
-    for(i=0; i<5; i++){
-      sqlite3_bind_value(pInsert, i+1, sqlite3_column_value(pSql, i));
+  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;
     }
-    sqlite3_step(pInsert);
-    p->rc = sqlite3_reset(pInsert);
+    rbuFinalize(p, pXInfo);
+    bIndex = 1;
+    pIter->nIndex++;
   }
-  if( p->rc==SQLITE_OK ){
-    p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=0",0,0,&p->zErrmsg);
+
+  if( pIter->eType==RBU_PK_WITHOUT_ROWID ){
+    /* "PRAGMA index_list" includes the main PK b-tree */
+    pIter->nIndex--;
   }
 
-  rbuFinalize(p, pSql);
-  rbuFinalize(p, pInsert);
+  rbuFinalize(p, pList);
+  if( bIndex==0 ) pIter->abIndexed = 0;
 }
 
+
 /*
-** Step the RBU object.
+** 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.
 */
-SQLITE_API int sqlite3rbu_step(sqlite3rbu *p){
-  if( p ){
-    switch( p->eStage ){
-      case RBU_STAGE_OAL: {
-        RbuObjIter *pIter = &p->objiter;
-
-        /* If this is an RBU vacuum operation and the state table was empty
-        ** when this handle was opened, create the target database schema. */
-        if( rbuIsVacuum(p) && p->nProgress==0 && p->rc==SQLITE_OK ){
-          rbuCreateTargetSchema(p);
-          rbuCopyPragma(p, "user_version");
-          rbuCopyPragma(p, "application_id");
-        }
+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;
 
-        while( p->rc==SQLITE_OK && pIter->zTbl ){
+    /* 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;
 
-          if( pIter->bCleanup ){
-            /* Clean up the rbu_tmp_xxx table for the previous table. It 
-            ** cannot be dropped as there are currently active SQL statements.
-            ** But the contents can be deleted.  */
-            if( rbuIsVacuum(p)==0 && pIter->abIndexed ){
-              rbuMPrintfExec(p, p->dbRbu, 
-                  "DELETE FROM %s.'rbu_tmp_%q'", p->zStateDb, pIter->zDataTbl
-              );
-            }
-          }else{
-            rbuObjIterPrepareAll(p, pIter, 0);
+    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
+    );
 
-            /* Advance to the next row to process. */
-            if( p->rc==SQLITE_OK ){
-              int rc = sqlite3_step(pIter->pSelect);
-              if( rc==SQLITE_ROW ){
-                p->nProgress++;
-                p->nStep++;
-                return rbuStep(p);
-              }
-              p->rc = sqlite3_reset(pIter->pSelect);
-              p->nStep = 0;
-            }
-          }
+    /* 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 && i<nCol; i++){
+      const char *zName = (const char*)sqlite3_column_name(pStmt, i);
+      if( sqlite3_strnicmp("rbu_", zName, 4) ){
+        char *zCopy = rbuStrndup(zName, &p->rc);
+        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;
 
-          rbuObjIterNext(p, pIter);
-        }
+    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")
+      );
+    }
 
-        if( p->rc==SQLITE_OK ){
-          assert( pIter->zTbl==0 );
-          rbuSaveState(p, RBU_STAGE_MOVE);
-          rbuIncrSchemaCookie(p);
-          if( p->rc==SQLITE_OK ){
-            p->rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, &p->zErrmsg);
-          }
-          if( p->rc==SQLITE_OK ){
-            p->rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, &p->zErrmsg);
-          }
-          p->eStage = RBU_STAGE_MOVE;
-        }
-        break;
+    /* 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; i<pIter->nTblCol; 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);
 
-      case RBU_STAGE_MOVE: {
-        if( p->rc==SQLITE_OK ){
-          rbuMoveOalFile(p);
-          p->nProgress++;
+        if( i!=iOrder ){
+          SWAP(int, pIter->aiSrcOrder[i], pIter->aiSrcOrder[iOrder]);
+          SWAP(char*, pIter->azTblCol[i], pIter->azTblCol[iOrder]);
         }
-        break;
-      }
 
-      case RBU_STAGE_CKPT: {
-        if( p->rc==SQLITE_OK ){
-          if( p->nStep>=p->nFrame ){
-            sqlite3_file *pDb = p->pTargetFd->pReal;
-  
-            /* Sync the db file */
-            p->rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
-  
-            /* Update nBackfill */
-            if( p->rc==SQLITE_OK ){
-              void volatile *ptr;
-              p->rc = pDb->pMethods->xShmMap(pDb, 0, 32*1024, 0, &ptr);
-              if( p->rc==SQLITE_OK ){
-                ((u32 volatile*)ptr)[24] = p->iMaxFrame;
-              }
-            }
-  
-            if( p->rc==SQLITE_OK ){
-              p->eStage = RBU_STAGE_DONE;
-              p->rc = SQLITE_DONE;
-            }
-          }else{
-            /* At one point the following block copied a single frame from the
-            ** wal file to the database file. So that one call to sqlite3rbu_step()
-            ** checkpointed a single frame. 
-            **
-            ** However, if the sector-size is larger than the page-size, and the
-            ** application calls sqlite3rbu_savestate() or close() immediately
-            ** after this step, then rbu_step() again, then a power failure occurs,
-            ** then the database page written here may be damaged. Work around
-            ** this by checkpointing frames until the next page in the aFrame[]
-            ** lies on a different disk sector to the current one. */
-            u32 iSector;
-            do{
-              RbuFrame *pFrame = &p->aFrame[p->nStep];
-              iSector = (pFrame->iDbPage-1) / p->nPagePerSector;
-              rbuCheckpointFrame(p, pFrame);
-              p->nStep++;
-            }while( p->nStep<p->nFrame 
-                 && iSector==((p->aFrame[p->nStep].iDbPage-1) / p->nPagePerSector)
-                 && p->rc==SQLITE_OK
-            );
-          }
-          p->nProgress++;
-        }
-        break;
+        pIter->azTblType[iOrder] = rbuStrndup(zType, &p->rc);
+        pIter->abTblPk[iOrder] = (iPk!=0);
+        pIter->abNotNull[iOrder] = (u8)bNotNull || (iPk!=0);
+        iOrder++;
       }
-
-      default:
-        break;
     }
-    return p->rc;
-  }else{
-    return SQLITE_NOMEM;
+
+    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;
 }
 
 /*
-** Compare strings z1 and z2, returning 0 if they are identical, or non-zero
-** otherwise. Either or both argument may be NULL. Two NULL values are
-** considered equal, and NULL is considered distinct from all other values.
+** 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 int rbuStrCompare(const char *z1, const char *z2){
-  if( z1==0 && z2==0 ) return 0;
-  if( z1==0 || z2==0 ) return 1;
-  return (sqlite3_stricmp(z1, z2)!=0);
+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; i<pIter->nTblCol; i++){
+    const char *z = pIter->azTblCol[i];
+    zList = rbuMPrintf(p, "%z%s\"%w\"", zList, zSep, z);
+    zSep = ", ";
+  }
+  return zList;
 }
 
 /*
-** This function is called as part of sqlite3rbu_open() when initializing
-** an rbu handle in OAL stage. If the rbu update has not started (i.e.
-** the rbu_state table was empty) it is a no-op. Otherwise, it arranges
-** things so that the next call to sqlite3rbu_step() continues on from
-** where the previous rbu handle left off.
+** This function is used to create a SELECT list (the list of SQL 
+** expressions that follows a SELECT keyword) for a SELECT statement 
+** used to read from an data_xxx or rbu_tmp_xxx table while updating the 
+** index object currently indicated by the iterator object passed as the 
+** second argument. A "PRAGMA index_xinfo = <idxname>" statement is used 
+** to obtain the required information.
 **
-** If an error occurs, an error code and error message are left in the
-** rbu handle passed as the first argument.
+** 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 void rbuSetupOal(sqlite3rbu *p, RbuState *pState){
-  assert( p->rc==SQLITE_OK );
-  if( pState->zTbl ){
-    RbuObjIter *pIter = &p->objiter;
-    int rc = SQLITE_OK;
+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 = ? */
 
-    while( rc==SQLITE_OK && pIter->zTbl && (pIter->bCleanup 
-       || rbuStrCompare(pIter->zIdx, pState->zIdx)
-       || (pState->zDataTbl==0 && rbuStrCompare(pIter->zTbl, pState->zTbl))
-       || (pState->zDataTbl && rbuStrCompare(pIter->zDataTbl, pState->zDataTbl))
-    )){
-      rc = rbuObjIterNext(p, pIter);
-    }
+  if( rc==SQLITE_OK ){
+    assert( p->zErrmsg==0 );
+    rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg,
+        sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", pIter->zIdx)
+    );
+  }
 
-    if( rc==SQLITE_OK && !pIter->zTbl ){
-      rc = SQLITE_ERROR;
-      p->zErrmsg = sqlite3_mprintf("rbu_state mismatch error");
+  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( i<pIter->nTblCol );
+        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];
     }
 
-    if( rc==SQLITE_OK ){
-      p->nStep = pState->nRow;
-      rc = rbuObjIterPrepareAll(p, &p->objiter, p->nStep);
+    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;
 }
 
 /*
-** If there is a "*-oal" file in the file-system corresponding to the
-** target database in the file-system, delete it. If an error occurs,
-** leave an error code and error message in the rbu handle.
+** 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 void rbuDeleteOalFile(sqlite3rbu *p){
-  char *zOal = rbuMPrintf(p, "%s-oal", p->zTarget);
-  if( zOal ){
-    sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
-    assert( pVfs && p->rc==SQLITE_OK && p->zErrmsg==0 );
-    pVfs->xDelete(pVfs, zOal, 0);
-    sqlite3_free(zOal);
+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; i<pIter->nTblCol; 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;
 }
 
 /*
-** Allocate a private rbu VFS for the rbu handle passed as the only
-** argument. This VFS will be used unless the call to sqlite3rbu_open()
-** specified a URI with a vfs=? option in place of a target database
-** file name.
+** 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 void rbuCreateVfs(sqlite3rbu *p){
-  int rnd;
-  char zRnd[64];
+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; i<pIter->nTblCol; 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
+    );
 
-  assert( p->rc==SQLITE_OK );
-  sqlite3_randomness(sizeof(int), (void*)&rnd);
-  sqlite3_snprintf(sizeof(zRnd), zRnd, "rbu_vfs_%d", rnd);
-  p->rc = sqlite3rbu_create_vfs(zRnd, 0);
-  if( p->rc==SQLITE_OK ){
-    sqlite3_vfs *pVfs = sqlite3_vfs_find(zRnd);
-    assert( pVfs );
-    p->zVfsName = pVfs->zName;
-    ((rbu_vfs*)pVfs)->pRbu = p;
+  }else{
+    const char *zSep = "";
+    int i;
+    for(i=0; i<pIter->nTblCol; 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;
 }
 
 /*
-** Destroy the private VFS created for the rbu handle passed as the only
-** argument by an earlier call to rbuCreateVfs().
+** 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 rbuDeleteVfs(sqlite3rbu *p){
-  if( p->zVfsName ){
-    sqlite3rbu_destroy_vfs(p->zVfsName);
-    p->zVfsName = 0;
-  }
+static void rbuBadControlError(sqlite3rbu *p){
+  p->rc = SQLITE_ERROR;
+  p->zErrmsg = sqlite3_mprintf("invalid rbu_control value");
 }
 
+
 /*
-** This user-defined SQL function is invoked with a single argument - the
-** name of a table expected to appear in the target database. It returns
-** the number of auxilliary indexes on the table.
+** 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 void rbuIndexCntFunc(
-  sqlite3_context *pCtx, 
-  int nVal,
-  sqlite3_value **apVal
+static char *rbuObjIterGetSetlist(
+  sqlite3rbu *p,
+  RbuObjIter *pIter,
+  const char *zMask
 ){
-  sqlite3rbu *p = (sqlite3rbu*)sqlite3_user_data(pCtx);
-  sqlite3_stmt *pStmt = 0;
-  char *zErrmsg = 0;
-  int rc;
+  char *zList = 0;
+  if( p->rc==SQLITE_OK ){
+    int i;
 
-  assert( nVal==1 );
-  
-  rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &zErrmsg, 
-      sqlite3_mprintf("SELECT count(*) FROM sqlite_master "
-        "WHERE type='index' AND tbl_name = %Q", sqlite3_value_text(apVal[0]))
-  );
-  if( rc!=SQLITE_OK ){
-    sqlite3_result_error(pCtx, zErrmsg, -1);
-  }else{
-    int nIndex = 0;
-    if( SQLITE_ROW==sqlite3_step(pStmt) ){
-      nIndex = sqlite3_column_int(pStmt, 0);
-    }
-    rc = sqlite3_finalize(pStmt);
-    if( rc==SQLITE_OK ){
-      sqlite3_result_int(pCtx, nIndex);
+    if( (int)strlen(zMask)!=pIter->nTblCol ){
+      rbuBadControlError(p);
     }else{
-      sqlite3_result_error(pCtx, sqlite3_errmsg(p->dbMain), -1);
+      const char *zSep = "";
+      for(i=0; i<pIter->nTblCol; 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;
+}
 
-  sqlite3_free(zErrmsg);
+/*
+** 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; i<nBind; i++){
+      zRet[i*2] = '?';
+      zRet[i*2+1] = (i+1==nBind) ? '\0' : ',';
+    }
+  }
+  return zRet;
 }
 
 /*
-** If the RBU database contains the rbu_count table, use it to initialize
-** the sqlite3rbu.nPhaseOneStep variable. The schema of the rbu_count table
-** is assumed to contain the same columns as:
+** The iterator currently points to a table (not index) of type 
+** RBU_PK_WITHOUT_ROWID. This function creates the PRIMARY KEY 
+** declaration for the corresponding imposter table. For example,
+** if the iterator points to a table created as:
 **
-**   CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID;
+**   CREATE TABLE t1(a, b, c, PRIMARY KEY(b, a DESC)) WITHOUT ROWID
 **
-** There should be one row in the table for each data_xxx table in the
-** database. The 'tbl' column should contain the name of a data_xxx table,
-** and the cnt column the number of rows it contains.
+** this function returns:
 **
-** sqlite3rbu.nPhaseOneStep is initialized to the sum of (1 + nIndex) * cnt
-** for all rows in the rbu_count table, where nIndex is the number of 
-** indexes on the corresponding target database table.
+**   PRIMARY KEY("b", "a" DESC)
 */
-static void rbuInitPhaseOneSteps(sqlite3rbu *p){
+static char *rbuWithoutRowidPK(sqlite3rbu *p, RbuObjIter *pIter){
+  char *z = 0;
+  assert( pIter->zIdx==0 );
   if( p->rc==SQLITE_OK ){
-    sqlite3_stmt *pStmt = 0;
-    int bExists = 0;                /* True if rbu_count exists */
-
-    p->nPhaseOneStep = -1;
-
-    p->rc = sqlite3_create_function(p->dbRbu, 
-        "rbu_index_cnt", 1, SQLITE_UTF8, (void*)p, rbuIndexCntFunc, 0, 0
+    const char *zSep = "PRIMARY KEY(";
+    sqlite3_stmt *pXList = 0;     /* PRAGMA index_list = (pIter->zTbl) */
+    sqlite3_stmt *pXInfo = 0;     /* PRAGMA index_xinfo = <pk-index> */
+   
+    p->rc = prepareFreeAndCollectError(p->dbMain, &pXList, &p->zErrmsg,
+        sqlite3_mprintf("PRAGMA main.index_list = %Q", pIter->zTbl)
     );
-  
-    /* Check for the rbu_count table. If it does not exist, or if an error
-    ** occurs, nPhaseOneStep will be left set to -1. */
-    if( p->rc==SQLITE_OK ){
-      p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
-          "SELECT 1 FROM sqlite_master WHERE tbl_name = 'rbu_count'"
-      );
-    }
-    if( p->rc==SQLITE_OK ){
-      if( SQLITE_ROW==sqlite3_step(pStmt) ){
-        bExists = 1;
+    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;
       }
-      p->rc = sqlite3_finalize(pStmt);
     }
-  
-    if( p->rc==SQLITE_OK && bExists ){
-      p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
-          "SELECT sum(cnt * (1 + rbu_index_cnt(rbu_target_name(tbl))))"
-          "FROM rbu_count"
-      );
-      if( p->rc==SQLITE_OK ){
-        if( SQLITE_ROW==sqlite3_step(pStmt) ){
-          p->nPhaseOneStep = sqlite3_column_int64(pStmt, 0);
-        }
-        p->rc = sqlite3_finalize(pStmt);
+    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 */
 
-static sqlite3rbu *openRbuHandle(
-  const char *zTarget, 
-  const char *zRbu,
-  const char *zState
-){
-  sqlite3rbu *p;
-  size_t nTarget = zTarget ? strlen(zTarget) : 0;
-  size_t nRbu = strlen(zRbu);
-  size_t nByte = sizeof(sqlite3rbu) + nTarget+1 + nRbu+1;
-
-  p = (sqlite3rbu*)sqlite3_malloc64(nByte);
-  if( p ){
-    RbuState *pState = 0;
-
-    /* Create the custom VFS. */
-    memset(p, 0, sizeof(sqlite3rbu));
-    rbuCreateVfs(p);
-
-    /* Open the target, RBU and state databases */
-    if( p->rc==SQLITE_OK ){
-      char *pCsr = (char*)&p[1];
-      int bRetry = 0;
-      if( zTarget ){
-        p->zTarget = pCsr;
-        memcpy(p->zTarget, zTarget, nTarget+1);
-        pCsr += nTarget+1;
-      }
-      p->zRbu = pCsr;
-      memcpy(p->zRbu, zRbu, nRbu+1);
-      pCsr += nRbu+1;
-      if( zState ){
-        p->zState = rbuMPrintf(p, "%s", zState);
-      }
-
-      /* If the first attempt to open the database file fails and the bRetry
-      ** flag it set, this means that the db was not opened because it seemed
-      ** to be a wal-mode db. But, this may have happened due to an earlier
-      ** RBU vacuum operation leaving an old wal file in the directory.
-      ** If this is the case, it will have been checkpointed and deleted
-      ** when the handle was closed and a second attempt to open the 
-      ** database may succeed.  */
-      rbuOpenDatabase(p, &bRetry);
-      if( bRetry ){
-        rbuOpenDatabase(p, 0);
-      }
-    }
-
+    /* 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 ){
-      pState = rbuLoadState(p);
-      assert( pState || p->rc!=SQLITE_OK );
-      if( p->rc==SQLITE_OK ){
-
-        if( pState->eStage==0 ){ 
-          rbuDeleteOalFile(p);
-          rbuInitPhaseOneSteps(p);
-          p->eStage = RBU_STAGE_OAL;
-        }else{
-          p->eStage = pState->eStage;
-          p->nPhaseOneStep = pState->nPhaseOneStep;
-        }
-        p->nProgress = pState->nProgress;
-        p->iOalSz = pState->iOalSz;
+      sqlite3_bind_int(pQuery, 1, tnum);
+      if( SQLITE_ROW==sqlite3_step(pQuery) ){
+        zIdx = (const char*)sqlite3_column_text(pQuery, 0);
       }
     }
-    assert( p->rc!=SQLITE_OK || p->eStage!=0 );
-
-    if( p->rc==SQLITE_OK && p->pTargetFd->pWalFd ){
-      if( p->eStage==RBU_STAGE_OAL ){
-        p->rc = SQLITE_ERROR;
-        p->zErrmsg = sqlite3_mprintf("cannot update wal mode database");
-      }else if( p->eStage==RBU_STAGE_MOVE ){
-        p->eStage = RBU_STAGE_CKPT;
-        p->nStep = 0;
-      }
+    if( zIdx ){
+      p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg,
+          sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx)
+      );
     }
+    rbuFinalize(p, pQuery);
 
-    if( p->rc==SQLITE_OK 
-     && (p->eStage==RBU_STAGE_OAL || p->eStage==RBU_STAGE_MOVE)
-     && pState->eStage!=0
-    ){
-      rbu_file *pFd = (rbuIsVacuum(p) ? p->pRbuFd : p->pTargetFd);
-      if( pFd->iCookie!=pState->iCookie ){   
-        /* At this point (pTargetFd->iCookie) contains the value of the
-        ** change-counter cookie (the thing that gets incremented when a 
-        ** transaction is committed in rollback mode) currently stored on 
-        ** page 1 of the database file. */
-        p->rc = SQLITE_BUSY;
-        p->zErrmsg = sqlite3_mprintf("database modified during rbu %s",
-            (rbuIsVacuum(p) ? "vacuum" : "update")
+    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 %Q", 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);
 
-    if( p->rc==SQLITE_OK ){
-      if( p->eStage==RBU_STAGE_OAL ){
-        sqlite3 *db = p->dbMain;
-        p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, &p->zErrmsg);
-
-        /* Point the object iterator at the first object */
-        if( p->rc==SQLITE_OK ){
-          p->rc = rbuObjIterFirst(p, &p->objiter);
-        }
+    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 the RBU database contains no data_xxx tables, declare the RBU
-        ** update finished.  */
-        if( p->rc==SQLITE_OK && p->objiter.zTbl==0 ){
-          p->rc = SQLITE_DONE;
-          p->eStage = RBU_STAGE_DONE;
-        }else{
-          if( p->rc==SQLITE_OK && pState->eStage==0 && rbuIsVacuum(p) ){
-            rbuCopyPragma(p, "page_size");
-            rbuCopyPragma(p, "auto_vacuum");
-          }
+/*
+** 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);
 
-          /* Open transactions both databases. The *-oal file is opened or
-          ** created at this point. */
-          if( p->rc==SQLITE_OK ){
-            p->rc = sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
-          }
+    for(iCol=0; p->rc==SQLITE_OK && iCol<pIter->nTblCol; iCol++){
+      const char *zPk = "";
+      const char *zCol = pIter->azTblCol[iCol];
+      const char *zColl = 0;
 
-          /* Check if the main database is a zipvfs db. If it is, set the upper
-          ** level pager to use "journal_mode=off". This prevents it from 
-          ** generating a large journal using a temp file.  */
-          if( p->rc==SQLITE_OK ){
-            int frc = sqlite3_file_control(db, "main", SQLITE_FCNTL_ZIPVFS, 0);
-            if( frc==SQLITE_OK ){
-              p->rc = sqlite3_exec(
-                db, "PRAGMA journal_mode=off",0,0,&p->zErrmsg);
-            }
-          }
+      p->rc = sqlite3_table_column_metadata(
+          p->dbMain, "main", pIter->zTbl, zCol, 0, &zColl, 0, 0, 0
+      );
 
-          if( p->rc==SQLITE_OK ){
-            rbuSetupOal(p, pState);
-          }
-        }
-      }else if( p->eStage==RBU_STAGE_MOVE ){
-        /* no-op */
-      }else if( p->eStage==RBU_STAGE_CKPT ){
-        rbuSetupCheckpoint(p, pState);
-      }else if( p->eStage==RBU_STAGE_DONE ){
-        p->rc = SQLITE_DONE;
-      }else{
-        p->rc = SQLITE_CORRUPT;
+      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 %Q%s", 
+          zSql, zComma, zCol, pIter->azTblType[iCol], zPk, zColl,
+          (pIter->abNotNull[iCol] ? " NOT NULL" : "")
+      );
+      zComma = ", ";
     }
 
-    rbuFreeState(pState);
-  }
-
-  return p;
-}
+    if( pIter->eType==RBU_PK_WITHOUT_ROWID ){
+      char *zPk = rbuWithoutRowidPK(p, pIter);
+      if( zPk ){
+        zSql = rbuMPrintf(p, "%z, %z", zSql, zPk);
+      }
+    }
 
-/*
-** Allocate and return an RBU handle with all fields zeroed except for the
-** error code, which is set to SQLITE_MISUSE.
-*/
-static sqlite3rbu *rbuMisuseError(void){
-  sqlite3rbu *pRet;
-  pRet = sqlite3_malloc64(sizeof(sqlite3rbu));
-  if( pRet ){
-    memset(pRet, 0, sizeof(sqlite3rbu));
-    pRet->rc = SQLITE_MISUSE;
+    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);
   }
-  return pRet;
 }
 
 /*
-** Open and return a new RBU handle. 
+** 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.
 */
-SQLITE_API sqlite3rbu *sqlite3rbu_open(
-  const char *zTarget, 
-  const char *zRbu,
-  const char *zState
+static void rbuObjIterPrepareTmpInsert(
+  sqlite3rbu *p, 
+  RbuObjIter *pIter,
+  const char *zCollist,
+  const char *zRbuRowid
 ){
-  if( zTarget==0 || zRbu==0 ){ return rbuMisuseError(); }
-  /* TODO: Check that zTarget and zRbu are non-NULL */
-  return openRbuHandle(zTarget, zRbu, zState);
+  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
+    ));
+  }
 }
 
-/*
-** Open a handle to begin or resume an RBU VACUUM operation.
-*/
-SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
-  const char *zTarget, 
-  const char *zState
+static void rbuTmpInsertFunc(
+  sqlite3_context *pCtx, 
+  int nVal,
+  sqlite3_value **apVal
 ){
-  if( zTarget==0 ){ return rbuMisuseError(); }
-  /* TODO: Check that both arguments are non-NULL */
-  return openRbuHandle(0, zTarget, zState);
-}
+  sqlite3rbu *p = sqlite3_user_data(pCtx);
+  int rc = SQLITE_OK;
+  int i;
 
-/*
-** Return the database handle used by pRbu.
-*/
-SQLITE_API sqlite3 *sqlite3rbu_db(sqlite3rbu *pRbu, int bRbu){
-  sqlite3 *db = 0;
-  if( pRbu ){
-    db = (bRbu ? pRbu->dbRbu : pRbu->dbMain);
+  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;
   }
-  return db;
-}
 
+  for(i=0; rc==SQLITE_OK && i<nVal; i++){
+    rc = sqlite3_bind_value(p->objiter.pTmpInsert, i+1, apVal[i]);
+  }
+  if( rc==SQLITE_OK ){
+    sqlite3_step(p->objiter.pTmpInsert);
+    rc = sqlite3_reset(p->objiter.pTmpInsert);
+  }
 
-/*
-** If the error code currently stored in the RBU handle is SQLITE_CONSTRAINT,
-** then edit any error message string so as to remove all occurrences of
-** the pattern "rbu_imp_[0-9]*".
-*/
-static void rbuEditErrmsg(sqlite3rbu *p){
-  if( p->rc==SQLITE_CONSTRAINT && p->zErrmsg ){
-    unsigned int i;
-    size_t nErrmsg = strlen(p->zErrmsg);
-    for(i=0; i<(nErrmsg-8); i++){
-      if( memcmp(&p->zErrmsg[i], "rbu_imp_", 8)==0 ){
-        int nDel = 8;
-        while( p->zErrmsg[i+nDel]>='0' && p->zErrmsg[i+nDel]<='9' ) nDel++;
-        memmove(&p->zErrmsg[i], &p->zErrmsg[i+nDel], nErrmsg + 1 - i - nDel);
-        nErrmsg -= nDel;
-      }
-    }
+  if( rc!=SQLITE_OK ){
+    sqlite3_result_error_code(pCtx, rc);
   }
 }
 
 /*
-** Close the RBU handle.
+** 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.
 */
-SQLITE_API int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
-  int rc;
-  if( p ){
-
-    /* Commit the transaction to the *-oal file. */
-    if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_OAL ){
-      p->rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, &p->zErrmsg);
-    }
+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;
 
-    /* Sync the db file if currently doing an incremental checkpoint */
-    if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_CKPT ){
-      sqlite3_file *pDb = p->pTargetFd->pReal;
-      p->rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
+    if( nOffset ){
+      zLimit = sqlite3_mprintf(" LIMIT -1 OFFSET %d", nOffset);
+      if( !zLimit ) p->rc = SQLITE_NOMEM;
     }
 
-    rbuSaveState(p, p->eStage);
-
-    if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_OAL ){
-      p->rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, &p->zErrmsg);
-    }
+    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;
 
-    /* Close any open statement handles. */
-    rbuObjIterFinalize(&p->objiter);
+      assert( pIter->eType!=RBU_PK_VTAB );
+      zCollist = rbuObjIterGetIndexCols(
+          p, pIter, &zImposterCols, &zImposterPK, &zWhere, &nBind
+      );
+      zBind = rbuObjIterGetBindlist(p, nBind);
 
-    /* If this is an RBU vacuum handle and the vacuum has either finished
-    ** successfully or encountered an error, delete the contents of the 
-    ** state table. This causes the next call to sqlite3rbu_vacuum() 
-    ** specifying the current target and state databases to start a new
-    ** vacuum from scratch.  */
-    if( rbuIsVacuum(p) && p->rc!=SQLITE_OK && p->dbRbu ){
-      int rc2 = sqlite3_exec(p->dbRbu, "DELETE FROM stat.rbu_state", 0, 0, 0);
-      if( p->rc==SQLITE_DONE && rc2!=SQLITE_OK ) p->rc = rc2;
-    }
+      /* 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);
 
-    /* Close the open database handle and VFS object. */
-    sqlite3_close(p->dbRbu);
-    sqlite3_close(p->dbMain);
-    assert( p->szTemp==0 );
-    rbuDeleteVfs(p);
-    sqlite3_free(p->aBuf);
-    sqlite3_free(p->aFrame);
+      /* 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)
+        );
+      }
 
-    rbuEditErrmsg(p);
-    rc = p->rc;
-    if( pzErrmsg ){
-      *pzErrmsg = p->zErrmsg;
-    }else{
-      sqlite3_free(p->zErrmsg);
-    }
-    sqlite3_free(p->zState);
-    sqlite3_free(p);
-  }else{
-    rc = SQLITE_NOMEM;
-    *pzErrmsg = 0;
-  }
-  return rc;
-}
+      /* 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)
+        );
+      }
 
-/*
-** 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){
-  return pRbu->nProgress;
-}
+      /* 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
 
-/*
-** Return permyriadage progress indications for the two main stages of
-** an RBU update.
-*/
-SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *p, int *pnOne, int *pnTwo){
-  const int MAX_PROGRESS = 10000;
-  switch( p->eStage ){
-    case RBU_STAGE_OAL:
-      if( p->nPhaseOneStep>0 ){
-        *pnOne = (int)(MAX_PROGRESS * (i64)p->nProgress/(i64)p->nPhaseOneStep);
-      }else{
-        *pnOne = -1;
+        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);
       }
-      *pnTwo = 0;
-      break;
-
-    case RBU_STAGE_MOVE:
-      *pnOne = MAX_PROGRESS;
-      *pnTwo = 0;
-      break;
 
-    case RBU_STAGE_CKPT:
-      *pnOne = MAX_PROGRESS;
-      *pnTwo = (int)(MAX_PROGRESS * (i64)p->nStep / (i64)p->nFrame);
-      break;
+      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 */
 
-    case RBU_STAGE_DONE:
-      *pnOne = MAX_PROGRESS;
-      *pnTwo = MAX_PROGRESS;
-      break;
+      char *zBindings = rbuObjIterGetBindlist(p, pIter->nTblCol + bRbuRowid);
+      char *zWhere = rbuObjIterGetWhere(p, pIter);
+      char *zOldlist = rbuObjIterGetOldlist(p, pIter, "old");
+      char *zNewlist = rbuObjIterGetOldlist(p, pIter, "new");
 
-    default:
-      assert( 0 );
-  }
-}
+      zCollist = rbuObjIterGetCollist(p, pIter);
+      pIter->nCol = pIter->nTblCol;
 
-/*
-** Return the current state of the RBU vacuum or update operation.
-*/
-SQLITE_API int sqlite3rbu_state(sqlite3rbu *p){
-  int aRes[] = {
-    0, SQLITE_RBU_STATE_OAL, SQLITE_RBU_STATE_MOVE,
-    0, SQLITE_RBU_STATE_CHECKPOINT, SQLITE_RBU_STATE_DONE
-  };
+      /* Create the imposter table or tables (if required). */
+      rbuCreateImposterTable(p, pIter);
+      rbuCreateImposterTable2(p, pIter);
+      zWrite = (pIter->eType==RBU_PK_VTAB ? "" : "rbu_imp_");
 
-  assert( RBU_STAGE_OAL==1 );
-  assert( RBU_STAGE_MOVE==2 );
-  assert( RBU_STAGE_CKPT==4 );
-  assert( RBU_STAGE_DONE==5 );
-  assert( aRes[RBU_STAGE_OAL]==SQLITE_RBU_STATE_OAL );
-  assert( aRes[RBU_STAGE_MOVE]==SQLITE_RBU_STATE_MOVE );
-  assert( aRes[RBU_STAGE_CKPT]==SQLITE_RBU_STATE_CHECKPOINT );
-  assert( aRes[RBU_STAGE_DONE]==SQLITE_RBU_STATE_DONE );
+      /* 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
+            )
+        );
+      }
 
-  if( p->rc!=SQLITE_OK && p->rc!=SQLITE_DONE ){
-    return SQLITE_RBU_STATE_ERROR;
-  }else{
-    assert( p->rc!=SQLITE_DONE || p->eStage==RBU_STAGE_DONE );
-    assert( p->eStage==RBU_STAGE_OAL
-         || p->eStage==RBU_STAGE_MOVE
-         || p->eStage==RBU_STAGE_CKPT
-         || p->eStage==RBU_STAGE_DONE
-    );
-    return aRes[p->eStage];
-  }
-}
+      /* 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
+            )
+        );
+      }
 
-SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){
-  int rc = p->rc;
-  if( rc==SQLITE_DONE ) return SQLITE_OK;
+      if( rbuIsVacuum(p)==0 && pIter->abIndexed ){
+        const char *zRbuRowid = "";
+        if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){
+          zRbuRowid = ", rbu_rowid";
+        }
 
-  assert( p->eStage>=RBU_STAGE_OAL && p->eStage<=RBU_STAGE_DONE );
-  if( p->eStage==RBU_STAGE_OAL ){
-    assert( rc!=SQLITE_DONE );
-    if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, 0);
-  }
+        /* 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
+        );
 
-  /* Sync the db file */
-  if( rc==SQLITE_OK && p->eStage==RBU_STAGE_CKPT ){
-    sqlite3_file *pDb = p->pTargetFd->pReal;
-    rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
-  }
+        rbuMPrintfExec(p, p->dbMain,
+            "CREATE TEMP TRIGGER rbu_delete_tr BEFORE DELETE ON \"%s%w\" "
+            "BEGIN "
+            "  SELECT rbu_tmp_insert(3, %s);"
+            "END;"
 
-  p->rc = rc;
-  rbuSaveState(p, p->eStage);
-  rc = p->rc;
+            "CREATE TEMP TRIGGER rbu_update1_tr BEFORE UPDATE ON \"%s%w\" "
+            "BEGIN "
+            "  SELECT rbu_tmp_insert(3, %s);"
+            "END;"
 
-  if( p->eStage==RBU_STAGE_OAL ){
-    assert( rc!=SQLITE_DONE );
-    if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0);
-    if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbRbu, "BEGIN IMMEDIATE", 0, 0, 0);
-    if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "BEGIN IMMEDIATE", 0, 0,0);
-  }
+            "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
+        );
 
-  p->rc = rc;
-  return rc;
-}
+        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
+          );
+        }
 
-/**************************************************************************
-** Beginning of RBU VFS shim methods. The VFS shim modifies the behaviour
-** of a standard VFS in the following ways:
-**
-** 1. Whenever the first page of a main database file is read or 
-**    written, the value of the change-counter cookie is stored in
-**    rbu_file.iCookie. Similarly, the value of the "write-version"
-**    database header field is stored in rbu_file.iWriteVer. This ensures
-**    that the values are always trustworthy within an open transaction.
-**
-** 2. Whenever an SQLITE_OPEN_WAL file is opened, the (rbu_file.pWalFd)
-**    member variable of the associated database file descriptor is set
-**    to point to the new file. A mutex protected linked list of all main 
-**    db fds opened using a particular RBU VFS is maintained at 
-**    rbu_vfs.pMain to facilitate this.
-**
-** 3. Using a new file-control "SQLITE_FCNTL_RBU", a main db rbu_file 
-**    object can be marked as the target database of an RBU update. This
-**    turns on the following extra special behaviour:
-**
-** 3a. If xAccess() is called to check if there exists a *-wal file 
-**     associated with an RBU target database currently in RBU_STAGE_OAL
-**     stage (preparing the *-oal file), the following special handling
-**     applies:
-**
-**      * if the *-wal file does exist, return SQLITE_CANTOPEN. An RBU
-**        target database may not be in wal mode already.
-**
-**      * if the *-wal file does not exist, set the output parameter to
-**        non-zero (to tell SQLite that it does exist) anyway.
-**
-**     Then, when xOpen() is called to open the *-wal file associated with
-**     the RBU target in RBU_STAGE_OAL stage, instead of opening the *-wal
-**     file, the rbu vfs opens the corresponding *-oal file instead. 
-**
-** 3b. The *-shm pages returned by xShmMap() for a target db file in
-**     RBU_STAGE_OAL mode are actually stored in heap memory. This is to
-**     avoid creating a *-shm file on disk. Additionally, xShmLock() calls
-**     are no-ops on target database files in RBU_STAGE_OAL mode. This is
-**     because assert() statements in some VFS implementations fail if 
-**     xShmLock() is called before xShmMap().
-**
-** 3c. If an EXCLUSIVE lock is attempted on a target database file in any
-**     mode except RBU_STAGE_DONE (all work completed and checkpointed), it 
-**     fails with an SQLITE_BUSY error. This is to stop RBU connections
-**     from automatically checkpointing a *-wal (or *-oal) file from within
-**     sqlite3_close().
-**
-** 3d. In RBU_STAGE_CAPTURE mode, all xRead() calls on the wal file, and
-**     all xWrite() calls on the target database file perform no IO. 
-**     Instead the frame and page numbers that would be read and written
-**     are recorded. Additionally, successful attempts to obtain exclusive
-**     xShmLock() WRITER, CHECKPOINTER and READ0 locks on the target 
-**     database file are recorded. xShmLock() calls to unlock the same
-**     locks are no-ops (so that once obtained, these locks are never
-**     relinquished). Finally, calls to xSync() on the target database
-**     file fail with SQLITE_INTERNAL errors.
-*/
+        rbuObjIterPrepareTmpInsert(p, pIter, zCollist, zRbuRowid);
+      }
 
-static void rbuUnlockShm(rbu_file *p){
-  assert( p->openFlags & SQLITE_OPEN_MAIN_DB );
-  if( p->pRbu ){
-    int (*xShmLock)(sqlite3_file*,int,int,int) = p->pReal->pMethods->xShmLock;
-    int i;
-    for(i=0; i<SQLITE_SHM_NLOCK;i++){
-      if( (1<<i) & p->pRbu->mLock ){
-        xShmLock(p->pReal, i, 1, SQLITE_SHM_UNLOCK|SQLITE_SHM_EXCLUSIVE);
+      /* 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);
     }
-    p->pRbu->mLock = 0;
+    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 rbuUpdateTempSize(rbu_file *pFd, sqlite3_int64 nNew){
-  sqlite3rbu *pRbu = pFd->pRbu;
-  i64 nDiff = nNew - pFd->sz;
-  pRbu->szTemp += nDiff;
-  pFd->sz = nNew;
-  assert( pRbu->szTemp>=0 );
-  if( pRbu->szTempLimit && pRbu->szTemp>pRbu->szTempLimit ) return SQLITE_FULL;
-  return SQLITE_OK;
-}
+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;
 
-/*
-** Close an rbu file.
-*/
-static int rbuVfsClose(sqlite3_file *pFile){
-  rbu_file *p = (rbu_file*)pFile;
-  int rc;
-  int i;
+  /* In case an error occurs */
+  *ppStmt = 0;
 
-  /* Free the contents of the apShm[] array. And the array itself. */
-  for(i=0; i<p->nShm; i++){
-    sqlite3_free(p->apShm[i]);
+  /* 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++;
   }
-  sqlite3_free(p->apShm);
-  p->apShm = 0;
-  sqlite3_free(p->zDel);
+  assert( pUp==0 || pUp->pNext==0 );
 
-  if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
-    rbu_file **pp;
-    sqlite3_mutex_enter(p->pRbuVfs->mutex);
-    for(pp=&p->pRbuVfs->pMain; *pp!=p; pp=&((*pp)->pMainNext));
-    *pp = p->pMainNext;
-    sqlite3_mutex_leave(p->pRbuVfs->mutex);
-    rbuUnlockShm(p);
-    p->pReal->pMethods->xShmUnmap(p->pReal, 0);
-  }
-  else if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){
-    rbuUpdateTempSize(p, 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);
   }
 
-  /* Close the underlying file handle */
-  rc = p->pReal->pMethods->xClose(p->pReal);
-  return rc;
-}
-
-
-/*
-** Read and return an unsigned 32-bit big-endian integer from the buffer 
-** passed as the only argument.
-*/
-static u32 rbuGetU32(u8 *aBuf){
-  return ((u32)aBuf[0] << 24)
-       + ((u32)aBuf[1] << 16)
-       + ((u32)aBuf[2] <<  8)
-       + ((u32)aBuf[3]);
-}
-
-/*
-** Write an unsigned 32-bit value in big-endian format to the supplied
-** buffer.
-*/
-static void rbuPutU32(u8 *aBuf, u32 iVal){
-  aBuf[0] = (iVal >> 24) & 0xFF;
-  aBuf[1] = (iVal >> 16) & 0xFF;
-  aBuf[2] = (iVal >>  8) & 0xFF;
-  aBuf[3] = (iVal >>  0) & 0xFF;
-}
-
-static void rbuPutU16(u8 *aBuf, u16 iVal){
-  aBuf[0] = (iVal >>  8) & 0xFF;
-  aBuf[1] = (iVal >>  0) & 0xFF;
-}
+  if( pUp ){
+    char *zWhere = rbuObjIterGetWhere(p, pIter);
+    char *zSet = rbuObjIterGetSetlist(p, pIter, zMask);
+    char *zUpdate = 0;
 
-/*
-** Read data from an rbuVfs-file.
-*/
-static int rbuVfsRead(
-  sqlite3_file *pFile, 
-  void *zBuf, 
-  int iAmt, 
-  sqlite_int64 iOfst
-){
-  rbu_file *p = (rbu_file*)pFile;
-  sqlite3rbu *pRbu = p->pRbu;
-  int rc;
+    pUp->zMask = (char*)&pUp[1];
+    memcpy(pUp->zMask, zMask, pIter->nTblCol);
+    pUp->pNext = pIter->pRbuUpdate;
+    pIter->pRbuUpdate = pUp;
 
-  if( pRbu && pRbu->eStage==RBU_STAGE_CAPTURE ){
-    assert( p->openFlags & SQLITE_OPEN_WAL );
-    rc = rbuCaptureWalRead(p->pRbu, iOfst, iAmt);
-  }else{
-    if( pRbu && pRbu->eStage==RBU_STAGE_OAL 
-     && (p->openFlags & SQLITE_OPEN_WAL) 
-     && iOfst>=pRbu->iOalSz 
-    ){
-      rc = SQLITE_OK;
-      memset(zBuf, 0, iAmt);
-    }else{
-      rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
-#if 1
-      /* If this is being called to read the first page of the target 
-      ** database as part of an rbu vacuum operation, synthesize the 
-      ** contents of the first page if it does not yet exist. Otherwise,
-      ** SQLite will not check for a *-wal file.  */
-      if( pRbu && rbuIsVacuum(pRbu) 
-          && rc==SQLITE_IOERR_SHORT_READ && iOfst==0
-          && (p->openFlags & SQLITE_OPEN_MAIN_DB)
-          && pRbu->rc==SQLITE_OK
-      ){
-        sqlite3_file *pFd = (sqlite3_file*)pRbu->pRbuFd;
-        rc = pFd->pMethods->xRead(pFd, zBuf, iAmt, iOfst);
-        if( rc==SQLITE_OK ){
-          u8 *aBuf = (u8*)zBuf;
-          u32 iRoot = rbuGetU32(&aBuf[52]) ? 1 : 0;
-          rbuPutU32(&aBuf[52], iRoot);      /* largest root page number */
-          rbuPutU32(&aBuf[36], 0);          /* number of free pages */
-          rbuPutU32(&aBuf[32], 0);          /* first page on free list trunk */
-          rbuPutU32(&aBuf[28], 1);          /* size of db file in pages */
-          rbuPutU32(&aBuf[24], pRbu->pRbuFd->iCookie+1);  /* Change counter */
+    if( zSet ){
+      const char *zPrefix = "";
 
-          if( iAmt>100 ){
-            memset(&aBuf[100], 0, iAmt-100);
-            rbuPutU16(&aBuf[105], iAmt & 0xFFFF);
-            aBuf[100] = 0x0D;
-          }
-        }
-      }
-#endif
-    }
-    if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
-      /* These look like magic numbers. But they are stable, as they are part
-       ** of the definition of the SQLite file format, which may not change. */
-      u8 *pBuf = (u8*)zBuf;
-      p->iCookie = rbuGetU32(&pBuf[24]);
-      p->iWriteVer = pBuf[19];
+      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 rc;
+
+  return p->rc;
 }
 
-/*
-** Write data to an rbuVfs-file.
-*/
-static int rbuVfsWrite(
-  sqlite3_file *pFile, 
-  const void *zBuf, 
-  int iAmt, 
-  sqlite_int64 iOfst
+static sqlite3 *rbuOpenDbhandle(
+  sqlite3rbu *p, 
+  const char *zName, 
+  int bUseVfs
 ){
-  rbu_file *p = (rbu_file*)pFile;
-  sqlite3rbu *pRbu = p->pRbu;
-  int rc;
-
-  if( pRbu && pRbu->eStage==RBU_STAGE_CAPTURE ){
-    assert( p->openFlags & SQLITE_OPEN_MAIN_DB );
-    rc = rbuCaptureDbWrite(p->pRbu, iOfst);
-  }else{
-    if( pRbu ){
-      if( pRbu->eStage==RBU_STAGE_OAL 
-       && (p->openFlags & SQLITE_OPEN_WAL) 
-       && iOfst>=pRbu->iOalSz
-      ){
-        pRbu->iOalSz = iAmt + iOfst;
-      }else if( p->openFlags & SQLITE_OPEN_DELETEONCLOSE ){
-        i64 szNew = iAmt+iOfst;
-        if( szNew>p->sz ){
-          rc = rbuUpdateTempSize(p, szNew);
-          if( rc!=SQLITE_OK ) return rc;
-        }
-      }
-    }
-    rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
-    if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
-      /* These look like magic numbers. But they are stable, as they are part
-      ** of the definition of the SQLite file format, which may not change. */
-      u8 *pBuf = (u8*)zBuf;
-      p->iCookie = rbuGetU32(&pBuf[24]);
-      p->iWriteVer = pBuf[19];
+  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 rc;
-}
-
-/*
-** Truncate an rbuVfs-file.
-*/
-static int rbuVfsTruncate(sqlite3_file *pFile, sqlite_int64 size){
-  rbu_file *p = (rbu_file*)pFile;
-  if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){
-    int rc = rbuUpdateTempSize(p, size);
-    if( rc!=SQLITE_OK ) return rc;
-  }
-  return p->pReal->pMethods->xTruncate(p->pReal, size);
+  return db;
 }
 
 /*
-** Sync an rbuVfs-file.
+** Free an RbuState object allocated by rbuLoadState().
 */
-static int rbuVfsSync(sqlite3_file *pFile, int flags){
-  rbu_file *p = (rbu_file *)pFile;
-  if( p->pRbu && p->pRbu->eStage==RBU_STAGE_CAPTURE ){
-    if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
-      return SQLITE_INTERNAL;
-    }
-    return SQLITE_OK;
+static void rbuFreeState(RbuState *p){
+  if( p ){
+    sqlite3_free(p->zTbl);
+    sqlite3_free(p->zDataTbl);
+    sqlite3_free(p->zIdx);
+    sqlite3_free(p);
   }
-  return p->pReal->pMethods->xSync(p->pReal, flags);
 }
 
 /*
-** Return the current file-size of an rbuVfs-file.
+** 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 int rbuVfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
-  rbu_file *p = (rbu_file *)pFile;
+static RbuState *rbuLoadState(sqlite3rbu *p){
+  RbuState *pRet = 0;
+  sqlite3_stmt *pStmt = 0;
   int rc;
-  rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
+  int rc2;
 
-  /* If this is an RBU vacuum operation and this is the target database,
-  ** pretend that it has at least one page. Otherwise, SQLite will not
-  ** check for the existance of a *-wal file. rbuVfsRead() contains 
-  ** similar logic.  */
-  if( rc==SQLITE_OK && *pSize==0 
-   && p->pRbu && rbuIsVacuum(p->pRbu) 
-   && (p->openFlags & SQLITE_OPEN_MAIN_DB)
-  ){
-    *pSize = 1024;
-  }
-  return rc;
-}
+  pRet = (RbuState*)rbuMalloc(p, sizeof(RbuState));
+  if( pRet==0 ) return 0;
 
-/*
-** Lock an rbuVfs-file.
-*/
-static int rbuVfsLock(sqlite3_file *pFile, int eLock){
-  rbu_file *p = (rbu_file*)pFile;
-  sqlite3rbu *pRbu = p->pRbu;
-  int rc = SQLITE_OK;
+  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;
 
-  assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
-  if( eLock==SQLITE_LOCK_EXCLUSIVE 
-   && (p->bNolock || (pRbu && pRbu->eStage!=RBU_STAGE_DONE))
-  ){
-    /* Do not allow EXCLUSIVE locks. Preventing SQLite from taking this 
-    ** prevents it from checkpointing the database from sqlite3_close(). */
-    rc = SQLITE_BUSY;
-  }else{
-    rc = p->pReal->pMethods->xLock(p->pReal, eLock);
-  }
+      case RBU_STATE_TBL:
+        pRet->zTbl = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
+        break;
 
-  return rc;
-}
+      case RBU_STATE_IDX:
+        pRet->zIdx = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
+        break;
 
-/*
-** Unlock an rbuVfs-file.
-*/
-static int rbuVfsUnlock(sqlite3_file *pFile, int eLock){
-  rbu_file *p = (rbu_file *)pFile;
-  return p->pReal->pMethods->xUnlock(p->pReal, eLock);
-}
+      case RBU_STATE_ROW:
+        pRet->nRow = sqlite3_column_int(pStmt, 1);
+        break;
 
-/*
-** Check if another file-handle holds a RESERVED lock on an rbuVfs-file.
-*/
-static int rbuVfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){
-  rbu_file *p = (rbu_file *)pFile;
-  return p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
-}
+      case RBU_STATE_PROGRESS:
+        pRet->nProgress = sqlite3_column_int64(pStmt, 1);
+        break;
 
-/*
-** File control method. For custom operations on an rbuVfs-file.
-*/
-static int rbuVfsFileControl(sqlite3_file *pFile, int op, void *pArg){
-  rbu_file *p = (rbu_file *)pFile;
-  int (*xControl)(sqlite3_file*,int,void*) = p->pReal->pMethods->xFileControl;
-  int rc;
+      case RBU_STATE_CKPT:
+        pRet->iWalCksum = sqlite3_column_int64(pStmt, 1);
+        break;
 
-  assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB)
-       || p->openFlags & (SQLITE_OPEN_TRANSIENT_DB|SQLITE_OPEN_TEMP_JOURNAL)
-  );
-  if( op==SQLITE_FCNTL_RBU ){
-    sqlite3rbu *pRbu = (sqlite3rbu*)pArg;
+      case RBU_STATE_COOKIE:
+        pRet->iCookie = (u32)sqlite3_column_int64(pStmt, 1);
+        break;
 
-    /* First try to find another RBU vfs lower down in the vfs stack. If
-    ** one is found, this vfs will operate in pass-through mode. The lower
-    ** level vfs will do the special RBU handling.  */
-    rc = xControl(p->pReal, op, pArg);
+      case RBU_STATE_OALSZ:
+        pRet->iOalSz = (u32)sqlite3_column_int64(pStmt, 1);
+        break;
 
-    if( rc==SQLITE_NOTFOUND ){
-      /* Now search for a zipvfs instance lower down in the VFS stack. If
-      ** one is found, this is an error.  */
-      void *dummy = 0;
-      rc = xControl(p->pReal, SQLITE_FCNTL_ZIPVFS, &dummy);
-      if( rc==SQLITE_OK ){
-        rc = SQLITE_ERROR;
-        pRbu->zErrmsg = sqlite3_mprintf("rbu/zipvfs setup error");
-      }else if( rc==SQLITE_NOTFOUND ){
-        pRbu->pTargetFd = p;
-        p->pRbu = pRbu;
-        if( p->pWalFd ) p->pWalFd->pRbu = pRbu;
-        rc = SQLITE_OK;
-      }
-    }
-    return rc;
-  }
-  else if( op==SQLITE_FCNTL_RBUCNT ){
-    sqlite3rbu *pRbu = (sqlite3rbu*)pArg;
-    pRbu->nRbu++;
-    pRbu->pRbuFd = p;
-    p->bNolock = 1;
-  }
+      case RBU_STATE_PHASEONESTEP:
+        pRet->nPhaseOneStep = sqlite3_column_int64(pStmt, 1);
+        break;
 
-  rc = xControl(p->pReal, op, pArg);
-  if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){
-    rbu_vfs *pRbuVfs = p->pRbuVfs;
-    char *zIn = *(char**)pArg;
-    char *zOut = sqlite3_mprintf("rbu(%s)/%z", pRbuVfs->base.zName, zIn);
-    *(char**)pArg = zOut;
-    if( zOut==0 ) rc = SQLITE_NOMEM;
-  }
+      case RBU_STATE_DATATBL:
+        pRet->zDataTbl = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
+        break;
 
-  return rc;
-}
+      default:
+        rc = SQLITE_CORRUPT;
+        break;
+    }
+  }
+  rc2 = sqlite3_finalize(pStmt);
+  if( rc==SQLITE_OK ) rc = rc2;
 
-/*
-** Return the sector-size in bytes for an rbuVfs-file.
-*/
-static int rbuVfsSectorSize(sqlite3_file *pFile){
-  rbu_file *p = (rbu_file *)pFile;
-  return p->pReal->pMethods->xSectorSize(p->pReal);
+  p->rc = rc;
+  return pRet;
 }
 
-/*
-** Return the device characteristic flags supported by an rbuVfs-file.
-*/
-static int rbuVfsDeviceCharacteristics(sqlite3_file *pFile){
-  rbu_file *p = (rbu_file *)pFile;
-  return p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
-}
 
 /*
-** Take or release a shared-memory lock.
+** 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 int rbuVfsShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
-  rbu_file *p = (rbu_file*)pFile;
-  sqlite3rbu *pRbu = p->pRbu;
-  int rc = SQLITE_OK;
+static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
+  assert( p->rc || (p->dbMain==0 && p->dbRbu==0) );
+  assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 );
 
-#ifdef SQLITE_AMALGAMATION
-    assert( WAL_CKPT_LOCK==1 );
-#endif
+  /* Open the RBU database */
+  p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1);
 
-  assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
-  if( pRbu && (pRbu->eStage==RBU_STAGE_OAL || pRbu->eStage==RBU_STAGE_MOVE) ){
-    /* Magic number 1 is the WAL_CKPT_LOCK lock. Preventing SQLite from
-    ** taking this lock also prevents any checkpoints from occurring. 
-    ** todo: really, it's not clear why this might occur, as 
-    ** wal_autocheckpoint ought to be turned off.  */
-    if( ofst==WAL_LOCK_CKPT && n==1 ) rc = SQLITE_BUSY;
-  }else{
-    int bCapture = 0;
-    if( n==1 && (flags & SQLITE_SHM_EXCLUSIVE)
-     && pRbu && pRbu->eStage==RBU_STAGE_CAPTURE
-     && (ofst==WAL_LOCK_WRITE || ofst==WAL_LOCK_CKPT || ofst==WAL_LOCK_READ0)
-    ){
-      bCapture = 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( bCapture==0 || 0==(flags & SQLITE_SHM_UNLOCK) ){
-      rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
-      if( bCapture && rc==SQLITE_OK ){
-        pRbu->mLock |= (1 << ofst);
-      }
-    }
+  /* 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);
   }
 
-  return rc;
-}
+#if 0
+  if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){
+    p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, 0);
+  }
+#endif
 
-/*
-** Obtain a pointer to a mapping of a single 32KiB page of the *-shm file.
-*/
-static int rbuVfsShmMap(
-  sqlite3_file *pFile, 
-  int iRegion, 
-  int szRegion, 
-  int isWrite, 
-  void volatile **pp
-){
-  rbu_file *p = (rbu_file*)pFile;
-  int rc = SQLITE_OK;
-  int eStage = (p->pRbu ? p->pRbu->eStage : 0);
+  /* If it has not already been created, create the rbu_state table */
+  rbuMPrintfExec(p, p->dbRbu, RBU_CREATE_STATE, p->zStateDb);
 
-  /* If not in RBU_STAGE_OAL, allow this call to pass through. Or, if this
-  ** rbu is in the RBU_STAGE_OAL state, use heap memory for *-shm space 
-  ** instead of a file on disk.  */
-  assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
-  if( eStage==RBU_STAGE_OAL || eStage==RBU_STAGE_MOVE ){
-    if( iRegion<=p->nShm ){
-      int nByte = (iRegion+1) * sizeof(char*);
-      char **apNew = (char**)sqlite3_realloc64(p->apShm, nByte);
-      if( apNew==0 ){
-        rc = SQLITE_NOMEM;
-      }else{
-        memset(&apNew[p->nShm], 0, sizeof(char*) * (1 + iRegion - p->nShm));
-        p->apShm = apNew;
-        p->nShm = iRegion+1;
+#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( rc==SQLITE_OK && p->apShm[iRegion]==0 ){
-      char *pNew = (char*)sqlite3_malloc64(szRegion);
-      if( pNew==0 ){
-        rc = SQLITE_NOMEM;
-      }else{
-        memset(pNew, 0, szRegion);
-        p->apShm[iRegion] = pNew;
+      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( rc==SQLITE_OK ){
-      *pp = p->apShm[iRegion];
+  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{
-      *pp = 0;
+      RbuState *pState = rbuLoadState(p);
+      if( pState ){
+        bOpen = (pState->eStage>=RBU_STAGE_MOVE);
+        rbuFreeState(pState);
+      }
     }
-  }else{
-    assert( p->apShm==0 );
-    rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
+    if( bOpen ) p->dbMain = rbuOpenDbhandle(p, p->zRbu, p->nRbu<=1);
   }
 
-  return rc;
-}
-
-/*
-** Memory barrier.
-*/
-static void rbuVfsShmBarrier(sqlite3_file *pFile){
-  rbu_file *p = (rbu_file *)pFile;
-  p->pReal->pMethods->xShmBarrier(p->pReal);
-}
+  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;
+      }
 
-/*
-** The xShmUnmap method.
-*/
-static int rbuVfsShmUnmap(sqlite3_file *pFile, int delFlag){
-  rbu_file *p = (rbu_file*)pFile;
-  int rc = SQLITE_OK;
-  int eStage = (p->pRbu ? p->pRbu->eStage : 0);
+      zTarget = sqlite3_mprintf("file:%s-vacuum?rbu_memory=1%s%s", 
+          sqlite3_db_filename(p->dbRbu, "main"),
+          (zExtra==0 ? "" : "&"), (zExtra==0 ? "" : zExtra)
+      );
 
-  assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
-  if( eStage==RBU_STAGE_OAL || eStage==RBU_STAGE_MOVE ){
-    /* no-op */
-  }else{
-    /* Release the checkpointer and writer locks */
-    rbuUnlockShm(p);
-    rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
+      if( zTarget==0 ){
+        p->rc = SQLITE_NOMEM;
+        return;
+      }
+      p->dbMain = rbuOpenDbhandle(p, zTarget, p->nRbu<=1);
+      sqlite3_free(zTarget);
+    }
   }
-  return rc;
-}
 
-/*
-** Given that zWal points to a buffer containing a wal file name passed to 
-** either the xOpen() or xAccess() VFS method, return a pointer to the
-** file-handle opened by the same database connection on the corresponding
-** database file.
-*/
-static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal){
-  rbu_file *pDb;
-  sqlite3_mutex_enter(pRbuVfs->mutex);
-  for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){}
-  sqlite3_mutex_leave(pRbuVfs->mutex);
-  return pDb;
-}
+  if( p->rc==SQLITE_OK ){
+    p->rc = sqlite3_create_function(p->dbMain, 
+        "rbu_tmp_insert", -1, SQLITE_UTF8, (void*)p, rbuTmpInsertFunc, 0, 0
+    );
+  }
 
-/* 
-** A main database named zName has just been opened. The following 
-** function returns a pointer to a buffer owned by SQLite that contains
-** the name of the *-wal file this db connection will use. SQLite
-** happens to pass a pointer to this buffer when using xAccess()
-** or xOpen() to operate on the *-wal file.  
-*/
-static const char *rbuMainToWal(const char *zName, int flags){
-  int n = (int)strlen(zName);
-  const char *z = &zName[n];
-  if( flags & SQLITE_OPEN_URI ){
-    int odd = 0;
-    while( 1 ){
-      if( z[0]==0 ){
-        odd = 1 - odd;
-        if( odd && z[1]==0 ) break;
-      }
-      z++;
-    }
-    z += 2;
-  }else{
-    while( *z==0 ) z++;
+  if( p->rc==SQLITE_OK ){
+    p->rc = sqlite3_create_function(p->dbMain, 
+        "rbu_fossil_delta", 2, SQLITE_UTF8, 0, rbuFossilDeltaFunc, 0, 0
+    );
   }
-  z += (n + 8 + 1);
-  return z;
-}
 
-/*
-** Open an rbu file handle.
-*/
-static int rbuVfsOpen(
-  sqlite3_vfs *pVfs,
-  const char *zName,
-  sqlite3_file *pFile,
-  int flags,
-  int *pOutFlags
-){
-  static sqlite3_io_methods rbuvfs_io_methods = {
-    2,                            /* iVersion */
-    rbuVfsClose,                  /* xClose */
-    rbuVfsRead,                   /* xRead */
-    rbuVfsWrite,                  /* xWrite */
-    rbuVfsTruncate,               /* xTruncate */
-    rbuVfsSync,                   /* xSync */
-    rbuVfsFileSize,               /* xFileSize */
-    rbuVfsLock,                   /* xLock */
-    rbuVfsUnlock,                 /* xUnlock */
-    rbuVfsCheckReservedLock,      /* xCheckReservedLock */
-    rbuVfsFileControl,            /* xFileControl */
-    rbuVfsSectorSize,             /* xSectorSize */
-    rbuVfsDeviceCharacteristics,  /* xDeviceCharacteristics */
-    rbuVfsShmMap,                 /* xShmMap */
-    rbuVfsShmLock,                /* xShmLock */
-    rbuVfsShmBarrier,             /* xShmBarrier */
-    rbuVfsShmUnmap,               /* xShmUnmap */
-    0, 0                          /* xFetch, xUnfetch */
-  };
-  rbu_vfs *pRbuVfs = (rbu_vfs*)pVfs;
-  sqlite3_vfs *pRealVfs = pRbuVfs->pRealVfs;
-  rbu_file *pFd = (rbu_file *)pFile;
-  int rc = SQLITE_OK;
-  const char *zOpen = zName;
-  int oflags = flags;
+  if( p->rc==SQLITE_OK ){
+    p->rc = sqlite3_create_function(p->dbRbu, 
+        "rbu_target_name", -1, SQLITE_UTF8, (void*)p, rbuTargetNameFunc, 0, 0
+    );
+  }
 
-  memset(pFd, 0, sizeof(rbu_file));
-  pFd->pReal = (sqlite3_file*)&pFd[1];
-  pFd->pRbuVfs = pRbuVfs;
-  pFd->openFlags = flags;
-  if( zName ){
-    if( flags & SQLITE_OPEN_MAIN_DB ){
-      /* A main database has just been opened. The following block sets
-      ** (pFd->zWal) to point to a buffer owned by SQLite that contains
-      ** the name of the *-wal file this db connection will use. SQLite
-      ** happens to pass a pointer to this buffer when using xAccess()
-      ** or xOpen() to operate on the *-wal file.  */
-      pFd->zWal = rbuMainToWal(zName, flags);
-    }
-    else if( flags & SQLITE_OPEN_WAL ){
-      rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName);
-      if( pDb ){
-        if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
-          /* This call is to open a *-wal file. Intead, open the *-oal. This
-          ** code ensures that the string passed to xOpen() is terminated by a
-          ** pair of '\0' bytes in case the VFS attempts to extract a URI 
-          ** parameter from it.  */
-          const char *zBase = zName;
-          size_t nCopy;
-          char *zCopy;
-          if( rbuIsVacuum(pDb->pRbu) ){
-            zBase = sqlite3_db_filename(pDb->pRbu->dbRbu, "main");
-            zBase = rbuMainToWal(zBase, SQLITE_OPEN_URI);
-          }
-          nCopy = strlen(zBase);
-          zCopy = sqlite3_malloc64(nCopy+2);
-          if( zCopy ){
-            memcpy(zCopy, zBase, nCopy);
-            zCopy[nCopy-3] = 'o';
-            zCopy[nCopy] = '\0';
-            zCopy[nCopy+1] = '\0';
-            zOpen = (const char*)(pFd->zDel = zCopy);
-          }else{
-            rc = SQLITE_NOMEM;
-          }
-          pFd->pRbu = pDb->pRbu;
-        }
-        pDb->pWalFd = pFd;
-      }
-    }
-  }else{
-    pFd->pRbu = pRbuVfs->pRbu;
+  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");
 
-  if( oflags & SQLITE_OPEN_MAIN_DB 
-   && sqlite3_uri_boolean(zName, "rbu_memory", 0) 
-  ){
-    assert( oflags & SQLITE_OPEN_MAIN_DB );
-    oflags =  SQLITE_OPEN_TEMP_DB | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
-              SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE;
-    zOpen = 0;
+  /* 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( rc==SQLITE_OK ){
-    rc = pRealVfs->xOpen(pRealVfs, zOpen, pFd->pReal, oflags, pOutFlags);
+  if( p->rc==SQLITE_NOTFOUND ){
+    p->rc = SQLITE_ERROR;
+    p->zErrmsg = sqlite3_mprintf("rbu vfs not found");
   }
-  if( pFd->pReal->pMethods ){
-    /* The xOpen() operation has succeeded. Set the sqlite3_file.pMethods
-    ** pointer and, if the file is a main database file, link it into the
-    ** mutex protected linked list of all such files.  */
-    pFile->pMethods = &rbuvfs_io_methods;
-    if( flags & SQLITE_OPEN_MAIN_DB ){
-      sqlite3_mutex_enter(pRbuVfs->mutex);
-      pFd->pMainNext = pRbuVfs->pMain;
-      pRbuVfs->pMain = pFd;
-      sqlite3_mutex_leave(pRbuVfs->mutex);
-    }
-  }else{
-    sqlite3_free(pFd->zDel);
+}
+
+/*
+** 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);
   }
-
-  return rc;
+#endif
 }
 
 /*
-** Delete the file located at zPath.
+** 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 int rbuVfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
-  sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
-  return pRealVfs->xDelete(pRealVfs, zPath, dirSync);
+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;
 }
 
 /*
-** Test for access permissions. Return true if the requested permission
-** is available, or false otherwise.
+** 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 int rbuVfsAccess(
-  sqlite3_vfs *pVfs, 
-  const char *zPath, 
-  int flags, 
-  int *pResOut
-){
-  rbu_vfs *pRbuVfs = (rbu_vfs*)pVfs;
-  sqlite3_vfs *pRealVfs = pRbuVfs->pRealVfs;
-  int rc;
+static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){
 
-  rc = pRealVfs->xAccess(pRealVfs, zPath, flags, pResOut);
+  /* 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);
+    }
+  }
 
-  /* If this call is to check if a *-wal file associated with an RBU target
-  ** database connection exists, and the RBU update is in RBU_STAGE_OAL,
-  ** the following special handling is activated:
+  /* 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:
   **
-  **   a) if the *-wal file does exist, return SQLITE_CANTOPEN. This
-  **      ensures that the RBU extension never tries to update a database
-  **      in wal mode, even if the first page of the database file has
-  **      been damaged. 
+  **   * 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).
   **
-  **   b) if the *-wal file does not exist, claim that it does anyway,
-  **      causing SQLite to call xOpen() to open it. This call will also
-  **      be intercepted (see the rbuVfsOpen() function) and the *-oal
-  **      file opened instead.
+  **   * 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( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){
-    rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath);
-    if( pDb && pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
-      if( *pResOut ){
-        rc = SQLITE_CANTOPEN;
+  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{
-        sqlite3_int64 sz = 0;
-        rc = rbuVfsFileSize(&pDb->base, &sz);
-        *pResOut = (sz>0);
+        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);
     }
   }
-
-  return rc;
 }
 
 /*
-** Populate buffer zOut with the full canonical pathname corresponding
-** to the pathname in zPath. zOut is guaranteed to point to a buffer
-** of at least (DEVSYM_MAX_PATHNAME+1) bytes.
+** 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 rbuVfsFullPathname(
-  sqlite3_vfs *pVfs, 
-  const char *zPath, 
-  int nOut, 
-  char *zOut
-){
-  sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
-  return pRealVfs->xFullPathname(pRealVfs, zPath, nOut, zOut);
-}
+static int rbuCaptureWalRead(sqlite3rbu *pRbu, i64 iOff, int iAmt){
+  const u32 mReq = (1<<WAL_LOCK_WRITE)|(1<<WAL_LOCK_CKPT)|(1<<WAL_LOCK_READ0);
+  u32 iFrame;
 
-#ifndef SQLITE_OMIT_LOAD_EXTENSION
-/*
-** Open the dynamic library located at zPath and return a handle.
-*/
-static void *rbuVfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
-  sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
-  return pRealVfs->xDlOpen(pRealVfs, zPath);
+  if( pRbu->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<iFrame ) pRbu->iMaxFrame = iFrame;
+  pRbu->aFrame[pRbu->nFrame].iWalFrame = iFrame;
+  pRbu->aFrame[pRbu->nFrame].iDbPage = 0;
+  pRbu->nFrame++;
+  return SQLITE_OK;
 }
 
 /*
-** Populate the buffer zErrMsg (size nByte bytes) with a human readable
-** utf-8 string describing the most recent error encountered associated 
-** with dynamic libraries.
+** Called when a page of data is written to offset iOff of the database
+** file while the rbu handle is in capture mode. Record the page number 
+** of the page being written in the aFrame[] array.
 */
-static void rbuVfsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
-  sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
-  pRealVfs->xDlError(pRealVfs, nByte, zErrMsg);
+static int rbuCaptureDbWrite(sqlite3rbu *pRbu, i64 iOff){
+  pRbu->aFrame[pRbu->nFrame-1].iDbPage = (u32)(iOff / pRbu->pgsz) + 1;
+  return SQLITE_OK;
 }
 
 /*
-** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
+** This is called as part of an incremental checkpoint operation. Copy
+** a single frame of data from the wal file into the database file, as
+** indicated by the RbuFrame object.
 */
-static void (*rbuVfsDlSym(
-  sqlite3_vfs *pVfs, 
-  void *pArg, 
-  const char *zSym
-))(void){
-  sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
-  return pRealVfs->xDlSym(pRealVfs, pArg, zSym);
+static void rbuCheckpointFrame(sqlite3rbu *p, RbuFrame *pFrame){
+  sqlite3_file *pWal = p->pTargetFd->pWalFd->pReal;
+  sqlite3_file *pDb = p->pTargetFd->pReal;
+  i64 iOff;
+
+  assert( p->rc==SQLITE_OK );
+  iOff = (i64)(pFrame->iWalFrame-1) * (p->pgsz + 24) + 32 + 24;
+  p->rc = pWal->pMethods->xRead(pWal, p->aBuf, p->pgsz, iOff);
+  if( p->rc ) return;
+
+  iOff = (i64)(pFrame->iDbPage-1) * p->pgsz;
+  p->rc = pDb->pMethods->xWrite(pDb, p->aBuf, p->pgsz, iOff);
 }
 
+
 /*
-** Close the dynamic library handle pHandle.
+** Take an EXCLUSIVE lock on the database file.
 */
-static void rbuVfsDlClose(sqlite3_vfs *pVfs, void *pHandle){
-  sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
-  pRealVfs->xDlClose(pRealVfs, pHandle);
+static void rbuLockDatabase(sqlite3rbu *p){
+  sqlite3_file *pReal = p->pTargetFd->pReal;
+  assert( p->rc==SQLITE_OK );
+  p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_SHARED);
+  if( p->rc==SQLITE_OK ){
+    p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_EXCLUSIVE);
+  }
 }
-#endif /* SQLITE_OMIT_LOAD_EXTENSION */
 
-/*
-** Populate the buffer pointed to by zBufOut with nByte bytes of 
-** random data.
-*/
-static int rbuVfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
-  sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
-  return pRealVfs->xRandomness(pRealVfs, nByte, zBufOut);
+#if defined(_WIN32_WCE)
+static LPWSTR rbuWinUtf8ToUnicode(const char *zFilename){
+  int nChar;
+  LPWSTR zWideFilename;
+
+  nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
+  if( nChar==0 ){
+    return 0;
+  }
+  zWideFilename = sqlite3_malloc64( nChar*sizeof(zWideFilename[0]) );
+  if( zWideFilename==0 ){
+    return 0;
+  }
+  memset(zWideFilename, 0, nChar*sizeof(zWideFilename[0]));
+  nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename,
+                                nChar);
+  if( nChar==0 ){
+    sqlite3_free(zWideFilename);
+    zWideFilename = 0;
+  }
+  return zWideFilename;
 }
+#endif
 
 /*
-** Sleep for nMicro microseconds. Return the number of microseconds 
-** actually slept.
+** The RBU handle is currently in RBU_STAGE_OAL state, with a SHARED lock
+** on the database file. This proc moves the *-oal file to the *-wal path,
+** then reopens the database file (this time in vanilla, non-oal, WAL mode).
+** If an error occurs, leave an error code and error message in the rbu 
+** handle.
 */
-static int rbuVfsSleep(sqlite3_vfs *pVfs, int nMicro){
-  sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
-  return pRealVfs->xSleep(pRealVfs, nMicro);
+static void rbuMoveOalFile(sqlite3rbu *p){
+  const char *zBase = sqlite3_db_filename(p->dbMain, "main");
+  const char *zMove = zBase;
+  char *zOal;
+  char *zWal;
+
+  if( rbuIsVacuum(p) ){
+    zMove = sqlite3_db_filename(p->dbRbu, "main");
+  }
+  zOal = sqlite3_mprintf("%s-oal", zMove);
+  zWal = sqlite3_mprintf("%s-wal", zMove);
+
+  assert( p->eStage==RBU_STAGE_MOVE );
+  assert( p->rc==SQLITE_OK && p->zErrmsg==0 );
+  if( zWal==0 || zOal==0 ){
+    p->rc = SQLITE_NOMEM;
+  }else{
+    /* Move the *-oal file to *-wal. At this point connection p->db is
+    ** holding a SHARED lock on the target database file (because it is
+    ** in WAL mode). So no other connection may be writing the db. 
+    **
+    ** In order to ensure that there are no database readers, an EXCLUSIVE
+    ** lock is obtained here before the *-oal is moved to *-wal.
+    */
+    rbuLockDatabase(p);
+    if( p->rc==SQLITE_OK ){
+      rbuFileSuffix3(zBase, zWal);
+      rbuFileSuffix3(zBase, zOal);
+
+      /* Re-open the databases. */
+      rbuObjIterFinalize(&p->objiter);
+      sqlite3_close(p->dbRbu);
+      sqlite3_close(p->dbMain);
+      p->dbMain = 0;
+      p->dbRbu = 0;
+
+#if defined(_WIN32_WCE)
+      {
+        LPWSTR zWideOal;
+        LPWSTR zWideWal;
+
+        zWideOal = rbuWinUtf8ToUnicode(zOal);
+        if( zWideOal ){
+          zWideWal = rbuWinUtf8ToUnicode(zWal);
+          if( zWideWal ){
+            if( MoveFileW(zWideOal, zWideWal) ){
+              p->rc = SQLITE_OK;
+            }else{
+              p->rc = SQLITE_IOERR;
+            }
+            sqlite3_free(zWideWal);
+          }else{
+            p->rc = SQLITE_IOERR_NOMEM;
+          }
+          sqlite3_free(zWideOal);
+        }else{
+          p->rc = SQLITE_IOERR_NOMEM;
+        }
+      }
+#else
+      p->rc = rename(zOal, zWal) ? SQLITE_IOERR : SQLITE_OK;
+#endif
+
+      if( p->rc==SQLITE_OK ){
+        rbuOpenDatabase(p, 0);
+        rbuSetupCheckpoint(p, 0);
+      }
+    }
+  }
+
+  sqlite3_free(zWal);
+  sqlite3_free(zOal);
 }
 
 /*
-** Return the current time as a Julian Day number in *pTimeOut.
+** The SELECT statement iterating through the keys for the current object
+** (p->objiter.pSelect) currently points to a valid row. This function
+** determines the type of operation requested by this row and returns
+** one of the following values to indicate the result:
+**
+**     * RBU_INSERT
+**     * RBU_DELETE
+**     * RBU_IDX_DELETE
+**     * RBU_UPDATE
+**
+** If RBU_UPDATE is returned, then output variable *pzMask is set to
+** point to the text value indicating the columns to update.
+**
+** If the rbu_control field contains an invalid value, an error code and
+** message are left in the RBU handle and zero returned.
 */
-static int rbuVfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
-  sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
-  return pRealVfs->xCurrentTime(pRealVfs, pTimeOut);
+static int rbuStepType(sqlite3rbu *p, const char **pzMask){
+  int iCol = p->objiter.nCol;     /* Index of rbu_control column */
+  int res = 0;                    /* Return value */
+
+  switch( sqlite3_column_type(p->objiter.pSelect, iCol) ){
+    case SQLITE_INTEGER: {
+      int iVal = sqlite3_column_int(p->objiter.pSelect, iCol);
+      switch( iVal ){
+        case 0: res = RBU_INSERT;     break;
+        case 1: res = RBU_DELETE;     break;
+        case 2: res = RBU_REPLACE;    break;
+        case 3: res = RBU_IDX_DELETE; break;
+        case 4: res = RBU_IDX_INSERT; break;
+      }
+      break;
+    }
+
+    case SQLITE_TEXT: {
+      const unsigned char *z = sqlite3_column_text(p->objiter.pSelect, iCol);
+      if( z==0 ){
+        p->rc = SQLITE_NOMEM;
+      }else{
+        *pzMask = (const char*)z;
+      }
+      res = RBU_UPDATE;
+
+      break;
+    }
+
+    default:
+      break;
+  }
+
+  if( res==0 ){
+    rbuBadControlError(p);
+  }
+  return res;
 }
 
+#ifdef SQLITE_DEBUG
 /*
-** No-op.
+** Assert that column iCol of statement pStmt is named zName.
 */
-static int rbuVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){
-  return 0;
+static void assertColumnName(sqlite3_stmt *pStmt, int iCol, const char *zName){
+  const char *zCol = sqlite3_column_name(pStmt, iCol);
+  assert( 0==sqlite3_stricmp(zName, zCol) );
 }
+#else
+# define assertColumnName(x,y,z)
+#endif
 
 /*
-** Deregister and destroy an RBU vfs created by an earlier call to
-** sqlite3rbu_create_vfs().
+** Argument eType must be one of RBU_INSERT, RBU_DELETE, RBU_IDX_INSERT or
+** RBU_IDX_DELETE. This function performs the work of a single
+** sqlite3rbu_step() call for the type of operation specified by eType.
 */
-SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName){
-  sqlite3_vfs *pVfs = sqlite3_vfs_find(zName);
-  if( pVfs && pVfs->xOpen==rbuVfsOpen ){
-    sqlite3_mutex_free(((rbu_vfs*)pVfs)->mutex);
-    sqlite3_vfs_unregister(pVfs);
-    sqlite3_free(pVfs);
+static void rbuStepOneOp(sqlite3rbu *p, int eType){
+  RbuObjIter *pIter = &p->objiter;
+  sqlite3_value *pVal;
+  sqlite3_stmt *pWriter;
+  int i;
+
+  assert( p->rc==SQLITE_OK );
+  assert( eType!=RBU_DELETE || pIter->zIdx==0 );
+  assert( eType==RBU_DELETE || eType==RBU_IDX_DELETE
+       || eType==RBU_INSERT || eType==RBU_IDX_INSERT
+  );
+
+  /* If this is a delete, decrement nPhaseOneStep by nIndex. If the DELETE
+  ** statement below does actually delete a row, nPhaseOneStep will be
+  ** incremented by the same amount when SQL function rbu_tmp_insert()
+  ** is invoked by the trigger.  */
+  if( eType==RBU_DELETE ){
+    p->nPhaseOneStep -= p->objiter.nIndex;
   }
-}
 
-/*
-** Create an RBU VFS named zName that accesses the underlying file-system
-** via existing VFS zParent. The new object is registered as a non-default
-** VFS with SQLite before returning.
-*/
-SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent){
+  if( eType==RBU_IDX_DELETE || eType==RBU_DELETE ){
+    pWriter = pIter->pDelete;
+  }else{
+    pWriter = pIter->pInsert;
+  }
 
-  /* Template for VFS */
-  static sqlite3_vfs vfs_template = {
-    1,                            /* iVersion */
-    0,                            /* szOsFile */
-    0,                            /* mxPathname */
-    0,                            /* pNext */
-    0,                            /* zName */
-    0,                            /* pAppData */
-    rbuVfsOpen,                   /* xOpen */
-    rbuVfsDelete,                 /* xDelete */
-    rbuVfsAccess,                 /* xAccess */
-    rbuVfsFullPathname,           /* xFullPathname */
+  for(i=0; i<pIter->nCol; i++){
+    /* If this is an INSERT into a table b-tree and the table has an
+    ** explicit INTEGER PRIMARY KEY, check that this is not an attempt
+    ** to write a NULL into the IPK column. That is not permitted.  */
+    if( eType==RBU_INSERT 
+     && pIter->zIdx==0 && pIter->eType==RBU_PK_IPK && pIter->abTblPk[i] 
+     && sqlite3_column_type(pIter->pSelect, i)==SQLITE_NULL
+    ){
+      p->rc = SQLITE_MISMATCH;
+      p->zErrmsg = sqlite3_mprintf("datatype mismatch");
+      return;
+    }
 
-#ifndef SQLITE_OMIT_LOAD_EXTENSION
-    rbuVfsDlOpen,                 /* xDlOpen */
-    rbuVfsDlError,                /* xDlError */
-    rbuVfsDlSym,                  /* xDlSym */
-    rbuVfsDlClose,                /* xDlClose */
-#else
-    0, 0, 0, 0,
-#endif
+    if( eType==RBU_DELETE && pIter->abTblPk[i]==0 ){
+      continue;
+    }
 
-    rbuVfsRandomness,             /* xRandomness */
-    rbuVfsSleep,                  /* xSleep */
-    rbuVfsCurrentTime,            /* xCurrentTime */
-    rbuVfsGetLastError,           /* xGetLastError */
-    0,                            /* xCurrentTimeInt64 (version 2) */
-    0, 0, 0                       /* Unimplemented version 3 methods */
-  };
+    pVal = sqlite3_column_value(pIter->pSelect, i);
+    p->rc = sqlite3_bind_value(pWriter, i+1, pVal);
+    if( p->rc ) return;
+  }
+  if( pIter->zIdx==0 ){
+    if( pIter->eType==RBU_PK_VTAB 
+     || pIter->eType==RBU_PK_NONE 
+     || (pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p)) 
+    ){
+      /* For a virtual table, or a table with no primary key, the 
+      ** SELECT statement is:
+      **
+      **   SELECT <cols>, rbu_control, rbu_rowid FROM ....
+      **
+      ** Hence column_value(pIter->nCol+1).
+      */
+      assertColumnName(pIter->pSelect, pIter->nCol+1, 
+          rbuIsVacuum(p) ? "rowid" : "rbu_rowid"
+      );
+      pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
+      p->rc = sqlite3_bind_value(pWriter, pIter->nCol+1, pVal);
+    }
+  }
+  if( p->rc==SQLITE_OK ){
+    sqlite3_step(pWriter);
+    p->rc = resetAndCollectError(pWriter, &p->zErrmsg);
+  }
+}
 
-  rbu_vfs *pNew = 0;              /* Newly allocated VFS */
-  int rc = SQLITE_OK;
-  size_t nName;
-  size_t nByte;
+/*
+** This function does the work for an sqlite3rbu_step() call.
+**
+** The object-iterator (p->objiter) currently points to a valid object,
+** and the input cursor (p->objiter.pSelect) currently points to a valid
+** input row. Perform whatever processing is required and return.
+**
+** If no  error occurs, SQLITE_OK is returned. Otherwise, an error code
+** and message is left in the RBU handle and a copy of the error code
+** returned.
+*/
+static int rbuStep(sqlite3rbu *p){
+  RbuObjIter *pIter = &p->objiter;
+  const char *zMask = 0;
+  int eType = rbuStepType(p, &zMask);
 
-  nName = strlen(zName);
-  nByte = sizeof(rbu_vfs) + nName + 1;
-  pNew = (rbu_vfs*)sqlite3_malloc64(nByte);
-  if( pNew==0 ){
-    rc = SQLITE_NOMEM;
-  }else{
-    sqlite3_vfs *pParent;           /* Parent VFS */
-    memset(pNew, 0, nByte);
-    pParent = sqlite3_vfs_find(zParent);
-    if( pParent==0 ){
-      rc = SQLITE_NOTFOUND;
-    }else{
-      char *zSpace;
-      memcpy(&pNew->base, &vfs_template, sizeof(sqlite3_vfs));
-      pNew->base.mxPathname = pParent->mxPathname;
-      pNew->base.szOsFile = sizeof(rbu_file) + pParent->szOsFile;
-      pNew->pRealVfs = pParent;
-      pNew->base.zName = (const char*)(zSpace = (char*)&pNew[1]);
-      memcpy(zSpace, zName, nName);
+  if( eType ){
+    assert( eType==RBU_INSERT     || eType==RBU_DELETE
+         || eType==RBU_REPLACE    || eType==RBU_IDX_DELETE
+         || eType==RBU_IDX_INSERT || eType==RBU_UPDATE
+    );
+    assert( eType!=RBU_UPDATE || pIter->zIdx==0 );
 
-      /* Allocate the mutex and register the new VFS (not as the default) */
-      pNew->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE);
-      if( pNew->mutex==0 ){
-        rc = SQLITE_NOMEM;
-      }else{
-        rc = sqlite3_vfs_register(&pNew->base, 0);
+    if( pIter->zIdx==0 && (eType==RBU_IDX_DELETE || eType==RBU_IDX_INSERT) ){
+      rbuBadControlError(p);
+    }
+    else if( eType==RBU_REPLACE ){
+      if( pIter->zIdx==0 ){
+        p->nPhaseOneStep += p->objiter.nIndex;
+        rbuStepOneOp(p, RBU_DELETE);
       }
+      if( p->rc==SQLITE_OK ) rbuStepOneOp(p, RBU_INSERT);
     }
-
-    if( rc!=SQLITE_OK ){
-      sqlite3_mutex_free(pNew->mutex);
-      sqlite3_free(pNew);
+    else if( eType!=RBU_UPDATE ){
+      rbuStepOneOp(p, eType);
+    }
+    else{
+      sqlite3_value *pVal;
+      sqlite3_stmt *pUpdate = 0;
+      assert( eType==RBU_UPDATE );
+      p->nPhaseOneStep -= p->objiter.nIndex;
+      rbuGetUpdateStmt(p, pIter, zMask, &pUpdate);
+      if( pUpdate ){
+        int i;
+        for(i=0; p->rc==SQLITE_OK && i<pIter->nCol; i++){
+          char c = zMask[pIter->aiSrcOrder[i]];
+          pVal = sqlite3_column_value(pIter->pSelect, i);
+          if( pIter->abTblPk[i] || c!='.' ){
+            p->rc = sqlite3_bind_value(pUpdate, i+1, pVal);
+          }
+        }
+        if( p->rc==SQLITE_OK 
+         && (pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE) 
+        ){
+          /* Bind the rbu_rowid value to column _rowid_ */
+          assertColumnName(pIter->pSelect, pIter->nCol+1, "rbu_rowid");
+          pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
+          p->rc = sqlite3_bind_value(pUpdate, pIter->nCol+1, pVal);
+        }
+        if( p->rc==SQLITE_OK ){
+          sqlite3_step(pUpdate);
+          p->rc = resetAndCollectError(pUpdate, &p->zErrmsg);
+        }
+      }
     }
   }
-
-  return rc;
+  return p->rc;
 }
 
 /*
-** Configure the aggregate temp file size limit for this RBU handle.
+** Increment the schema cookie of the main database opened by p->dbMain.
+**
+** Or, if this is an RBU vacuum, set the schema cookie of the main db
+** opened by p->dbMain to one more than the schema cookie of the main
+** db opened by p->dbRbu.
 */
-SQLITE_API sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu *pRbu, sqlite3_int64 n){
-  if( n>=0 ){
-    pRbu->szTempLimit = n;
+static void rbuIncrSchemaCookie(sqlite3rbu *p){
+  if( p->rc==SQLITE_OK ){
+    sqlite3 *dbread = (rbuIsVacuum(p) ? p->dbRbu : p->dbMain);
+    int iCookie = 1000000;
+    sqlite3_stmt *pStmt;
+
+    p->rc = prepareAndCollectError(dbread, &pStmt, &p->zErrmsg, 
+        "PRAGMA schema_version"
+    );
+    if( p->rc==SQLITE_OK ){
+      /* Coverage: it may be that this sqlite3_step() cannot fail. There
+      ** is already a transaction open, so the prepared statement cannot
+      ** throw an SQLITE_SCHEMA exception. The only database page the
+      ** statement reads is page 1, which is guaranteed to be in the cache.
+      ** And no memory allocations are required.  */
+      if( SQLITE_ROW==sqlite3_step(pStmt) ){
+        iCookie = sqlite3_column_int(pStmt, 0);
+      }
+      rbuFinalize(p, pStmt);
+    }
+    if( p->rc==SQLITE_OK ){
+      rbuMPrintfExec(p, p->dbMain, "PRAGMA schema_version = %d", iCookie+1);
+    }
   }
-  return pRbu->szTempLimit;
 }
 
-SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu *pRbu){
-  return pRbu->szTemp;
-}
+/*
+** Update the contents of the rbu_state table within the rbu database. The
+** value stored in the RBU_STATE_STAGE column is eStage. All other values
+** are determined by inspecting the rbu handle passed as the first argument.
+*/
+static void rbuSaveState(sqlite3rbu *p, int eStage){
+  if( p->rc==SQLITE_OK || p->rc==SQLITE_DONE ){
+    sqlite3_stmt *pInsert = 0;
+    rbu_file *pFd = (rbuIsVacuum(p) ? p->pRbuFd : p->pTargetFd);
+    int rc;
 
+    assert( p->zErrmsg==0 );
+    rc = prepareFreeAndCollectError(p->dbRbu, &pInsert, &p->zErrmsg, 
+        sqlite3_mprintf(
+          "INSERT OR REPLACE INTO %s.rbu_state(k, v) VALUES "
+          "(%d, %d), "
+          "(%d, %Q), "
+          "(%d, %Q), "
+          "(%d, %d), "
+          "(%d, %d), "
+          "(%d, %lld), "
+          "(%d, %lld), "
+          "(%d, %lld), "
+          "(%d, %lld), "
+          "(%d, %Q)  ",
+          p->zStateDb,
+          RBU_STATE_STAGE, eStage,
+          RBU_STATE_TBL, p->objiter.zTbl, 
+          RBU_STATE_IDX, p->objiter.zIdx, 
+          RBU_STATE_ROW, p->nStep, 
+          RBU_STATE_PROGRESS, p->nProgress,
+          RBU_STATE_CKPT, p->iWalCksum,
+          RBU_STATE_COOKIE, (i64)pFd->iCookie,
+          RBU_STATE_OALSZ, p->iOalSz,
+          RBU_STATE_PHASEONESTEP, p->nPhaseOneStep,
+          RBU_STATE_DATATBL, p->objiter.zDataTbl
+      )
+    );
+    assert( pInsert==0 || rc==SQLITE_OK );
 
-/**************************************************************************/
+    if( rc==SQLITE_OK ){
+      sqlite3_step(pInsert);
+      rc = sqlite3_finalize(pInsert);
+    }
+    if( rc!=SQLITE_OK ) p->rc = rc;
+  }
+}
 
-#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU) */
 
-/************** End of sqlite3rbu.c ******************************************/
-/************** Begin file dbstat.c ******************************************/
 /*
-** 2010 July 12
-**
-** The author disclaims copyright to this source code.  In place of
-** a legal notice, here is a blessing:
+** The second argument passed to this function is the name of a PRAGMA 
+** setting - "page_size", "auto_vacuum", "user_version" or "application_id".
+** This function executes the following on sqlite3rbu.dbRbu:
 **
-**    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.
+**   "PRAGMA main.$zPragma"
 **
-******************************************************************************
+** where $zPragma is the string passed as the second argument, then
+** on sqlite3rbu.dbMain:
 **
-** This file contains an implementation of the "dbstat" virtual table.
+**   "PRAGMA main.$zPragma = $val"
 **
-** The dbstat virtual table is used to extract low-level formatting
-** information from an SQLite database in order to implement the
-** "sqlite3_analyzer" utility.  See the ../tool/spaceanal.tcl script
-** for an example implementation.
+** where $val is the value returned by the first PRAGMA invocation.
 **
-** Additional information is available on the "dbstat.html" page of the
-** official SQLite documentation.
+** In short, it copies the value  of the specified PRAGMA setting from
+** dbRbu to dbMain.
 */
-
-/* #include "sqliteInt.h"   ** Requires access to internal data structures ** */
-#if (defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)) \
-    && !defined(SQLITE_OMIT_VIRTUALTABLE)
+static void rbuCopyPragma(sqlite3rbu *p, const char *zPragma){
+  if( p->rc==SQLITE_OK ){
+    sqlite3_stmt *pPragma = 0;
+    p->rc = prepareFreeAndCollectError(p->dbRbu, &pPragma, &p->zErrmsg, 
+        sqlite3_mprintf("PRAGMA main.%s", zPragma)
+    );
+    if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPragma) ){
+      p->rc = rbuMPrintfExec(p, p->dbMain, "PRAGMA main.%s = %d",
+          zPragma, sqlite3_column_int(pPragma, 0)
+      );
+    }
+    rbuFinalize(p, pPragma);
+  }
+}
 
 /*
-** Page paths:
-** 
-**   The value of the 'path' column describes the path taken from the 
-**   root-node of the b-tree structure to each page. The value of the 
-**   root-node path is '/'.
-**
-**   The value of the path for the left-most child page of the root of
-**   a b-tree is '/000/'. (Btrees store content ordered from left to right
-**   so the pages to the left have smaller keys than the pages to the right.)
-**   The next to left-most child of the root page is
-**   '/001', and so on, each sibling page identified by a 3-digit hex 
-**   value. The children of the 451st left-most sibling have paths such
-**   as '/1c2/000/, '/1c2/001/' etc.
-**
-**   Overflow pages are specified by appending a '+' character and a 
-**   six-digit hexadecimal value to the path to the cell they are linked
-**   from. For example, the three overflow pages in a chain linked from 
-**   the left-most cell of the 450th child of the root page are identified
-**   by the paths:
-**
-**      '/1c2/000+000000'         // First page in overflow chain
-**      '/1c2/000+000001'         // Second page in overflow chain
-**      '/1c2/000+000002'         // Third page in overflow chain
-**
-**   If the paths are sorted using the BINARY collation sequence, then
-**   the overflow pages associated with a cell will appear earlier in the
-**   sort-order than its child page:
-**
-**      '/1c2/000/'               // Left-most child of 451st child of root
+** The RBU handle passed as the only argument has just been opened and 
+** the state database is empty. If this RBU handle was opened for an
+** RBU vacuum operation, create the schema in the target db.
 */
-#define VTAB_SCHEMA                                                         \
-  "CREATE TABLE xx( "                                                       \
-  "  name       TEXT,             /* Name of table or index */"             \
-  "  path       TEXT,             /* Path to page from root */"             \
-  "  pageno     INTEGER,          /* Page number */"                        \
-  "  pagetype   TEXT,             /* 'internal', 'leaf' or 'overflow' */"   \
-  "  ncell      INTEGER,          /* Cells on page (0 for overflow) */"     \
-  "  payload    INTEGER,          /* Bytes of payload on this page */"      \
-  "  unused     INTEGER,          /* Bytes of unused space on this page */" \
-  "  mx_payload INTEGER,          /* Largest payload size of all cells */"  \
-  "  pgoffset   INTEGER,          /* Offset of page in file */"             \
-  "  pgsize     INTEGER,          /* Size of the page */"                   \
-  "  schema     TEXT HIDDEN       /* Database schema being analyzed */"     \
-  ");"
+static void rbuCreateTargetSchema(sqlite3rbu *p){
+  sqlite3_stmt *pSql = 0;
+  sqlite3_stmt *pInsert = 0;
 
+  assert( rbuIsVacuum(p) );
+  p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=1", 0,0, &p->zErrmsg);
+  if( p->rc==SQLITE_OK ){
+    p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg, 
+      "SELECT sql FROM sqlite_master WHERE sql!='' AND rootpage!=0"
+      " AND name!='sqlite_sequence' "
+      " ORDER BY type DESC"
+    );
+  }
 
-typedef struct StatTable StatTable;
-typedef struct StatCursor StatCursor;
-typedef struct StatPage StatPage;
-typedef struct StatCell StatCell;
+  while( p->rc==SQLITE_OK && sqlite3_step(pSql)==SQLITE_ROW ){
+    const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
+    p->rc = sqlite3_exec(p->dbMain, zSql, 0, 0, &p->zErrmsg);
+  }
+  rbuFinalize(p, pSql);
+  if( p->rc!=SQLITE_OK ) return;
 
-struct StatCell {
-  int nLocal;                     /* Bytes of local payload */
-  u32 iChildPg;                   /* Child node (or 0 if this is a leaf) */
-  int nOvfl;                      /* Entries in aOvfl[] */
-  u32 *aOvfl;                     /* Array of overflow page numbers */
-  int nLastOvfl;                  /* Bytes of payload on final overflow page */
-  int iOvfl;                      /* Iterates through aOvfl[] */
-};
+  if( p->rc==SQLITE_OK ){
+    p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg, 
+        "SELECT * FROM sqlite_master WHERE rootpage=0 OR rootpage IS NULL" 
+    );
+  }
 
-struct StatPage {
-  u32 iPgno;
-  DbPage *pPg;
-  int iCell;
+  if( p->rc==SQLITE_OK ){
+    p->rc = prepareAndCollectError(p->dbMain, &pInsert, &p->zErrmsg, 
+        "INSERT INTO sqlite_master VALUES(?,?,?,?,?)"
+    );
+  }
 
-  char *zPath;                    /* Path to this page */
+  while( p->rc==SQLITE_OK && sqlite3_step(pSql)==SQLITE_ROW ){
+    int i;
+    for(i=0; i<5; i++){
+      sqlite3_bind_value(pInsert, i+1, sqlite3_column_value(pSql, i));
+    }
+    sqlite3_step(pInsert);
+    p->rc = sqlite3_reset(pInsert);
+  }
+  if( p->rc==SQLITE_OK ){
+    p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=0",0,0,&p->zErrmsg);
+  }
 
-  /* Variables populated by statDecodePage(): */
-  u8 flags;                       /* Copy of flags byte */
-  int nCell;                      /* Number of cells on page */
-  int nUnused;                    /* Number of unused bytes on page */
-  StatCell *aCell;                /* Array of parsed cells */
-  u32 iRightChildPg;              /* Right-child page number (or 0) */
-  int nMxPayload;                 /* Largest payload of any cell on this page */
-};
+  rbuFinalize(p, pSql);
+  rbuFinalize(p, pInsert);
+}
 
-struct StatCursor {
-  sqlite3_vtab_cursor base;
-  sqlite3_stmt *pStmt;            /* Iterates through set of root pages */
-  int isEof;                      /* After pStmt has returned SQLITE_DONE */
-  int iDb;                        /* Schema used for this query */
+/*
+** Step the RBU object.
+*/
+SQLITE_API int sqlite3rbu_step(sqlite3rbu *p){
+  if( p ){
+    switch( p->eStage ){
+      case RBU_STAGE_OAL: {
+        RbuObjIter *pIter = &p->objiter;
 
-  StatPage aPage[32];
-  int iPage;                      /* Current entry in aPage[] */
+        /* If this is an RBU vacuum operation and the state table was empty
+        ** when this handle was opened, create the target database schema. */
+        if( rbuIsVacuum(p) && p->nProgress==0 && p->rc==SQLITE_OK ){
+          rbuCreateTargetSchema(p);
+          rbuCopyPragma(p, "user_version");
+          rbuCopyPragma(p, "application_id");
+        }
 
-  /* Values to return. */
-  char *zName;                    /* Value of 'name' column */
-  char *zPath;                    /* Value of 'path' column */
-  u32 iPageno;                    /* Value of 'pageno' column */
-  char *zPagetype;                /* Value of 'pagetype' column */
-  int nCell;                      /* Value of 'ncell' column */
-  int nPayload;                   /* Value of 'payload' column */
-  int nUnused;                    /* Value of 'unused' column */
-  int nMxPayload;                 /* Value of 'mx_payload' column */
-  i64 iOffset;                    /* Value of 'pgOffset' column */
-  int szPage;                     /* Value of 'pgSize' column */
-};
+        while( p->rc==SQLITE_OK && pIter->zTbl ){
 
-struct StatTable {
-  sqlite3_vtab base;
-  sqlite3 *db;
-  int iDb;                        /* Index of database to analyze */
-};
+          if( pIter->bCleanup ){
+            /* Clean up the rbu_tmp_xxx table for the previous table. It 
+            ** cannot be dropped as there are currently active SQL statements.
+            ** But the contents can be deleted.  */
+            if( rbuIsVacuum(p)==0 && pIter->abIndexed ){
+              rbuMPrintfExec(p, p->dbRbu, 
+                  "DELETE FROM %s.'rbu_tmp_%q'", p->zStateDb, pIter->zDataTbl
+              );
+            }
+          }else{
+            rbuObjIterPrepareAll(p, pIter, 0);
 
-#ifndef get2byte
-# define get2byte(x)   ((x)[0]<<8 | (x)[1])
-#endif
+            /* Advance to the next row to process. */
+            if( p->rc==SQLITE_OK ){
+              int rc = sqlite3_step(pIter->pSelect);
+              if( rc==SQLITE_ROW ){
+                p->nProgress++;
+                p->nStep++;
+                return rbuStep(p);
+              }
+              p->rc = sqlite3_reset(pIter->pSelect);
+              p->nStep = 0;
+            }
+          }
 
-/*
-** Connect to or create a statvfs virtual table.
-*/
-static int statConnect(
-  sqlite3 *db,
-  void *pAux,
-  int argc, const char *const*argv,
-  sqlite3_vtab **ppVtab,
-  char **pzErr
-){
-  StatTable *pTab = 0;
-  int rc = SQLITE_OK;
-  int iDb;
+          rbuObjIterNext(p, pIter);
+        }
 
-  if( argc>=4 ){
-    Token nm;
-    sqlite3TokenInit(&nm, (char*)argv[3]);
-    iDb = sqlite3FindDb(db, &nm);
-    if( iDb<0 ){
-      *pzErr = sqlite3_mprintf("no such database: %s", argv[3]);
-      return SQLITE_ERROR;
-    }
-  }else{
-    iDb = 0;
-  }
-  rc = sqlite3_declare_vtab(db, VTAB_SCHEMA);
-  if( rc==SQLITE_OK ){
-    pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable));
-    if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
-  }
+        if( p->rc==SQLITE_OK ){
+          assert( pIter->zTbl==0 );
+          rbuSaveState(p, RBU_STAGE_MOVE);
+          rbuIncrSchemaCookie(p);
+          if( p->rc==SQLITE_OK ){
+            p->rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, &p->zErrmsg);
+          }
+          if( p->rc==SQLITE_OK ){
+            p->rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, &p->zErrmsg);
+          }
+          p->eStage = RBU_STAGE_MOVE;
+        }
+        break;
+      }
+
+      case RBU_STAGE_MOVE: {
+        if( p->rc==SQLITE_OK ){
+          rbuMoveOalFile(p);
+          p->nProgress++;
+        }
+        break;
+      }
+
+      case RBU_STAGE_CKPT: {
+        if( p->rc==SQLITE_OK ){
+          if( p->nStep>=p->nFrame ){
+            sqlite3_file *pDb = p->pTargetFd->pReal;
+  
+            /* Sync the db file */
+            p->rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
+  
+            /* Update nBackfill */
+            if( p->rc==SQLITE_OK ){
+              void volatile *ptr;
+              p->rc = pDb->pMethods->xShmMap(pDb, 0, 32*1024, 0, &ptr);
+              if( p->rc==SQLITE_OK ){
+                ((u32 volatile*)ptr)[24] = p->iMaxFrame;
+              }
+            }
+  
+            if( p->rc==SQLITE_OK ){
+              p->eStage = RBU_STAGE_DONE;
+              p->rc = SQLITE_DONE;
+            }
+          }else{
+            /* At one point the following block copied a single frame from the
+            ** wal file to the database file. So that one call to sqlite3rbu_step()
+            ** checkpointed a single frame. 
+            **
+            ** However, if the sector-size is larger than the page-size, and the
+            ** application calls sqlite3rbu_savestate() or close() immediately
+            ** after this step, then rbu_step() again, then a power failure occurs,
+            ** then the database page written here may be damaged. Work around
+            ** this by checkpointing frames until the next page in the aFrame[]
+            ** lies on a different disk sector to the current one. */
+            u32 iSector;
+            do{
+              RbuFrame *pFrame = &p->aFrame[p->nStep];
+              iSector = (pFrame->iDbPage-1) / p->nPagePerSector;
+              rbuCheckpointFrame(p, pFrame);
+              p->nStep++;
+            }while( p->nStep<p->nFrame 
+                 && iSector==((p->aFrame[p->nStep].iDbPage-1) / p->nPagePerSector)
+                 && p->rc==SQLITE_OK
+            );
+          }
+          p->nProgress++;
+        }
+        break;
+      }
 
-  assert( rc==SQLITE_OK || pTab==0 );
-  if( rc==SQLITE_OK ){
-    memset(pTab, 0, sizeof(StatTable));
-    pTab->db = db;
-    pTab->iDb = iDb;
+      default:
+        break;
+    }
+    return p->rc;
+  }else{
+    return SQLITE_NOMEM;
   }
-
-  *ppVtab = (sqlite3_vtab*)pTab;
-  return rc;
 }
 
 /*
-** Disconnect from or destroy a statvfs virtual table.
+** Compare strings z1 and z2, returning 0 if they are identical, or non-zero
+** otherwise. Either or both argument may be NULL. Two NULL values are
+** considered equal, and NULL is considered distinct from all other values.
 */
-static int statDisconnect(sqlite3_vtab *pVtab){
-  sqlite3_free(pVtab);
-  return SQLITE_OK;
+static int rbuStrCompare(const char *z1, const char *z2){
+  if( z1==0 && z2==0 ) return 0;
+  if( z1==0 || z2==0 ) return 1;
+  return (sqlite3_stricmp(z1, z2)!=0);
 }
 
 /*
-** There is no "best-index". This virtual table always does a linear
-** scan.  However, a schema=? constraint should cause this table to
-** operate on a different database schema, so check for it.
+** This function is called as part of sqlite3rbu_open() when initializing
+** an rbu handle in OAL stage. If the rbu update has not started (i.e.
+** the rbu_state table was empty) it is a no-op. Otherwise, it arranges
+** things so that the next call to sqlite3rbu_step() continues on from
+** where the previous rbu handle left off.
 **
-** idxNum is normally 0, but will be 1 if a schema=? constraint exists.
+** If an error occurs, an error code and error message are left in the
+** rbu handle passed as the first argument.
 */
-static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
-  int i;
+static void rbuSetupOal(sqlite3rbu *p, RbuState *pState){
+  assert( p->rc==SQLITE_OK );
+  if( pState->zTbl ){
+    RbuObjIter *pIter = &p->objiter;
+    int rc = SQLITE_OK;
 
-  pIdxInfo->estimatedCost = 1.0e6;  /* Initial cost estimate */
+    while( rc==SQLITE_OK && pIter->zTbl && (pIter->bCleanup 
+       || rbuStrCompare(pIter->zIdx, pState->zIdx)
+       || (pState->zDataTbl==0 && rbuStrCompare(pIter->zTbl, pState->zTbl))
+       || (pState->zDataTbl && rbuStrCompare(pIter->zDataTbl, pState->zDataTbl))
+    )){
+      rc = rbuObjIterNext(p, pIter);
+    }
 
-  /* Look for a valid schema=? constraint.  If found, change the idxNum to
-  ** 1 and request the value of that constraint be sent to xFilter.  And
-  ** lower the cost estimate to encourage the constrained version to be
-  ** used.
-  */
-  for(i=0; i<pIdxInfo->nConstraint; i++){
-    if( pIdxInfo->aConstraint[i].usable==0 ) continue;
-    if( pIdxInfo->aConstraint[i].op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
-    if( pIdxInfo->aConstraint[i].iColumn!=10 ) continue;
-    pIdxInfo->idxNum = 1;
-    pIdxInfo->estimatedCost = 1.0;
-    pIdxInfo->aConstraintUsage[i].argvIndex = 1;
-    pIdxInfo->aConstraintUsage[i].omit = 1;
-    break;
-  }
+    if( rc==SQLITE_OK && !pIter->zTbl ){
+      rc = SQLITE_ERROR;
+      p->zErrmsg = sqlite3_mprintf("rbu_state mismatch error");
+    }
 
+    if( rc==SQLITE_OK ){
+      p->nStep = pState->nRow;
+      rc = rbuObjIterPrepareAll(p, &p->objiter, p->nStep);
+    }
 
-  /* Records are always returned in ascending order of (name, path). 
-  ** If this will satisfy the client, set the orderByConsumed flag so that 
-  ** SQLite does not do an external sort.
-  */
-  if( ( pIdxInfo->nOrderBy==1
-     && pIdxInfo->aOrderBy[0].iColumn==0
-     && pIdxInfo->aOrderBy[0].desc==0
-     ) ||
-      ( pIdxInfo->nOrderBy==2
-     && pIdxInfo->aOrderBy[0].iColumn==0
-     && pIdxInfo->aOrderBy[0].desc==0
-     && pIdxInfo->aOrderBy[1].iColumn==1
-     && pIdxInfo->aOrderBy[1].desc==0
-     )
-  ){
-    pIdxInfo->orderByConsumed = 1;
+    p->rc = rc;
   }
-
-  return SQLITE_OK;
 }
 
 /*
-** Open a new statvfs cursor.
+** If there is a "*-oal" file in the file-system corresponding to the
+** target database in the file-system, delete it. If an error occurs,
+** leave an error code and error message in the rbu handle.
 */
-static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
-  StatTable *pTab = (StatTable *)pVTab;
-  StatCursor *pCsr;
-
-  pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor));
-  if( pCsr==0 ){
-    return SQLITE_NOMEM_BKPT;
-  }else{
-    memset(pCsr, 0, sizeof(StatCursor));
-    pCsr->base.pVtab = pVTab;
-    pCsr->iDb = pTab->iDb;
+static void rbuDeleteOalFile(sqlite3rbu *p){
+  char *zOal = rbuMPrintf(p, "%s-oal", p->zTarget);
+  if( zOal ){
+    sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
+    assert( pVfs && p->rc==SQLITE_OK && p->zErrmsg==0 );
+    pVfs->xDelete(pVfs, zOal, 0);
+    sqlite3_free(zOal);
   }
-
-  *ppCursor = (sqlite3_vtab_cursor *)pCsr;
-  return SQLITE_OK;
 }
 
-static void statClearPage(StatPage *p){
-  int i;
-  if( p->aCell ){
-    for(i=0; i<p->nCell; i++){
-      sqlite3_free(p->aCell[i].aOvfl);
-    }
-    sqlite3_free(p->aCell);
-  }
-  sqlite3PagerUnref(p->pPg);
-  sqlite3_free(p->zPath);
-  memset(p, 0, sizeof(StatPage));
-}
+/*
+** Allocate a private rbu VFS for the rbu handle passed as the only
+** argument. This VFS will be used unless the call to sqlite3rbu_open()
+** specified a URI with a vfs=? option in place of a target database
+** file name.
+*/
+static void rbuCreateVfs(sqlite3rbu *p){
+  int rnd;
+  char zRnd[64];
 
-static void statResetCsr(StatCursor *pCsr){
-  int i;
-  sqlite3_reset(pCsr->pStmt);
-  for(i=0; i<ArraySize(pCsr->aPage); i++){
-    statClearPage(&pCsr->aPage[i]);
+  assert( p->rc==SQLITE_OK );
+  sqlite3_randomness(sizeof(int), (void*)&rnd);
+  sqlite3_snprintf(sizeof(zRnd), zRnd, "rbu_vfs_%d", rnd);
+  p->rc = sqlite3rbu_create_vfs(zRnd, 0);
+  if( p->rc==SQLITE_OK ){
+    sqlite3_vfs *pVfs = sqlite3_vfs_find(zRnd);
+    assert( pVfs );
+    p->zVfsName = pVfs->zName;
+    ((rbu_vfs*)pVfs)->pRbu = p;
   }
-  pCsr->iPage = 0;
-  sqlite3_free(pCsr->zPath);
-  pCsr->zPath = 0;
-  pCsr->isEof = 0;
 }
 
 /*
-** Close a statvfs cursor.
+** Destroy the private VFS created for the rbu handle passed as the only
+** argument by an earlier call to rbuCreateVfs().
 */
-static int statClose(sqlite3_vtab_cursor *pCursor){
-  StatCursor *pCsr = (StatCursor *)pCursor;
-  statResetCsr(pCsr);
-  sqlite3_finalize(pCsr->pStmt);
-  sqlite3_free(pCsr);
-  return SQLITE_OK;
-}
-
-static void getLocalPayload(
-  int nUsable,                    /* Usable bytes per page */
-  u8 flags,                       /* Page flags */
-  int nTotal,                     /* Total record (payload) size */
-  int *pnLocal                    /* OUT: Bytes stored locally */
-){
-  int nLocal;
-  int nMinLocal;
-  int nMaxLocal;
-  if( flags==0x0D ){              /* Table leaf node */
-    nMinLocal = (nUsable - 12) * 32 / 255 - 23;
-    nMaxLocal = nUsable - 35;
-  }else{                          /* Index interior and leaf nodes */
-    nMinLocal = (nUsable - 12) * 32 / 255 - 23;
-    nMaxLocal = (nUsable - 12) * 64 / 255 - 23;
+static void rbuDeleteVfs(sqlite3rbu *p){
+  if( p->zVfsName ){
+    sqlite3rbu_destroy_vfs(p->zVfsName);
+    p->zVfsName = 0;
   }
-
-  nLocal = nMinLocal + (nTotal - nMinLocal) % (nUsable - 4);
-  if( nLocal>nMaxLocal ) nLocal = nMinLocal;
-  *pnLocal = nLocal;
 }
 
-static int statDecodePage(Btree *pBt, StatPage *p){
-  int nUnused;
-  int iOff;
-  int nHdr;
-  int isLeaf;
-  int szPage;
-
-  u8 *aData = sqlite3PagerGetData(p->pPg);
-  u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0];
-
-  p->flags = aHdr[0];
-  p->nCell = get2byte(&aHdr[3]);
-  p->nMxPayload = 0;
-
-  isLeaf = (p->flags==0x0A || p->flags==0x0D);
-  nHdr = 12 - isLeaf*4 + (p->iPgno==1)*100;
+/*
+** This user-defined SQL function is invoked with a single argument - the
+** name of a table expected to appear in the target database. It returns
+** the number of auxilliary indexes on the table.
+*/
+static void rbuIndexCntFunc(
+  sqlite3_context *pCtx, 
+  int nVal,
+  sqlite3_value **apVal
+){
+  sqlite3rbu *p = (sqlite3rbu*)sqlite3_user_data(pCtx);
+  sqlite3_stmt *pStmt = 0;
+  char *zErrmsg = 0;
+  int rc;
 
-  nUnused = get2byte(&aHdr[5]) - nHdr - 2*p->nCell;
-  nUnused += (int)aHdr[7];
-  iOff = get2byte(&aHdr[1]);
-  while( iOff ){
-    nUnused += get2byte(&aData[iOff+2]);
-    iOff = get2byte(&aData[iOff]);
+  assert( nVal==1 );
+  
+  rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &zErrmsg, 
+      sqlite3_mprintf("SELECT count(*) FROM sqlite_master "
+        "WHERE type='index' AND tbl_name = %Q", sqlite3_value_text(apVal[0]))
+  );
+  if( rc!=SQLITE_OK ){
+    sqlite3_result_error(pCtx, zErrmsg, -1);
+  }else{
+    int nIndex = 0;
+    if( SQLITE_ROW==sqlite3_step(pStmt) ){
+      nIndex = sqlite3_column_int(pStmt, 0);
+    }
+    rc = sqlite3_finalize(pStmt);
+    if( rc==SQLITE_OK ){
+      sqlite3_result_int(pCtx, nIndex);
+    }else{
+      sqlite3_result_error(pCtx, sqlite3_errmsg(p->dbMain), -1);
+    }
   }
-  p->nUnused = nUnused;
-  p->iRightChildPg = isLeaf ? 0 : sqlite3Get4byte(&aHdr[8]);
-  szPage = sqlite3BtreeGetPageSize(pBt);
 
-  if( p->nCell ){
-    int i;                        /* Used to iterate through cells */
-    int nUsable;                  /* Usable bytes per page */
+  sqlite3_free(zErrmsg);
+}
 
-    sqlite3BtreeEnter(pBt);
-    nUsable = szPage - sqlite3BtreeGetReserveNoMutex(pBt);
-    sqlite3BtreeLeave(pBt);
-    p->aCell = sqlite3_malloc64((p->nCell+1) * sizeof(StatCell));
-    if( p->aCell==0 ) return SQLITE_NOMEM_BKPT;
-    memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell));
+/*
+** If the RBU database contains the rbu_count table, use it to initialize
+** the sqlite3rbu.nPhaseOneStep variable. The schema of the rbu_count table
+** is assumed to contain the same columns as:
+**
+**   CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID;
+**
+** There should be one row in the table for each data_xxx table in the
+** database. The 'tbl' column should contain the name of a data_xxx table,
+** and the cnt column the number of rows it contains.
+**
+** sqlite3rbu.nPhaseOneStep is initialized to the sum of (1 + nIndex) * cnt
+** for all rows in the rbu_count table, where nIndex is the number of 
+** indexes on the corresponding target database table.
+*/
+static void rbuInitPhaseOneSteps(sqlite3rbu *p){
+  if( p->rc==SQLITE_OK ){
+    sqlite3_stmt *pStmt = 0;
+    int bExists = 0;                /* True if rbu_count exists */
 
-    for(i=0; i<p->nCell; i++){
-      StatCell *pCell = &p->aCell[i];
+    p->nPhaseOneStep = -1;
 
-      iOff = get2byte(&aData[nHdr+i*2]);
-      if( !isLeaf ){
-        pCell->iChildPg = sqlite3Get4byte(&aData[iOff]);
-        iOff += 4;
+    p->rc = sqlite3_create_function(p->dbRbu, 
+        "rbu_index_cnt", 1, SQLITE_UTF8, (void*)p, rbuIndexCntFunc, 0, 0
+    );
+  
+    /* Check for the rbu_count table. If it does not exist, or if an error
+    ** occurs, nPhaseOneStep will be left set to -1. */
+    if( p->rc==SQLITE_OK ){
+      p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
+          "SELECT 1 FROM sqlite_master WHERE tbl_name = 'rbu_count'"
+      );
+    }
+    if( p->rc==SQLITE_OK ){
+      if( SQLITE_ROW==sqlite3_step(pStmt) ){
+        bExists = 1;
       }
-      if( p->flags==0x05 ){
-        /* A table interior node. nPayload==0. */
-      }else{
-        u32 nPayload;             /* Bytes of payload total (local+overflow) */
-        int nLocal;               /* Bytes of payload stored locally */
-        iOff += getVarint32(&aData[iOff], nPayload);
-        if( p->flags==0x0D ){
-          u64 dummy;
-          iOff += sqlite3GetVarint(&aData[iOff], &dummy);
-        }
-        if( nPayload>(u32)p->nMxPayload ) p->nMxPayload = nPayload;
-        getLocalPayload(nUsable, p->flags, nPayload, &nLocal);
-        pCell->nLocal = nLocal;
-        assert( nLocal>=0 );
-        assert( nPayload>=(u32)nLocal );
-        assert( nLocal<=(nUsable-35) );
-        if( nPayload>(u32)nLocal ){
-          int j;
-          int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4);
-          pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
-          pCell->nOvfl = nOvfl;
-          pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl);
-          if( pCell->aOvfl==0 ) return SQLITE_NOMEM_BKPT;
-          pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]);
-          for(j=1; j<nOvfl; j++){
-            int rc;
-            u32 iPrev = pCell->aOvfl[j-1];
-            DbPage *pPg = 0;
-            rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPrev, &pPg, 0);
-            if( rc!=SQLITE_OK ){
-              assert( pPg==0 );
-              return rc;
-            } 
-            pCell->aOvfl[j] = sqlite3Get4byte(sqlite3PagerGetData(pPg));
-            sqlite3PagerUnref(pPg);
-          }
+      p->rc = sqlite3_finalize(pStmt);
+    }
+  
+    if( p->rc==SQLITE_OK && bExists ){
+      p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
+          "SELECT sum(cnt * (1 + rbu_index_cnt(rbu_target_name(tbl))))"
+          "FROM rbu_count"
+      );
+      if( p->rc==SQLITE_OK ){
+        if( SQLITE_ROW==sqlite3_step(pStmt) ){
+          p->nPhaseOneStep = sqlite3_column_int64(pStmt, 0);
         }
+        p->rc = sqlite3_finalize(pStmt);
       }
     }
   }
-
-  return SQLITE_OK;
 }
 
-/*
-** Populate the pCsr->iOffset and pCsr->szPage member variables. Based on
-** the current value of pCsr->iPageno.
-*/
-static void statSizeAndOffset(StatCursor *pCsr){
-  StatTable *pTab = (StatTable *)((sqlite3_vtab_cursor *)pCsr)->pVtab;
-  Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
-  Pager *pPager = sqlite3BtreePager(pBt);
-  sqlite3_file *fd;
-  sqlite3_int64 x[2];
 
-  /* The default page size and offset */
-  pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
-  pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1);
+static sqlite3rbu *openRbuHandle(
+  const char *zTarget, 
+  const char *zRbu,
+  const char *zState
+){
+  sqlite3rbu *p;
+  size_t nTarget = zTarget ? strlen(zTarget) : 0;
+  size_t nRbu = strlen(zRbu);
+  size_t nByte = sizeof(sqlite3rbu) + nTarget+1 + nRbu+1;
 
-  /* If connected to a ZIPVFS backend, override the page size and
-  ** offset with actual values obtained from ZIPVFS.
-  */
-  fd = sqlite3PagerFile(pPager);
-  x[0] = pCsr->iPageno;
-  if( sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){
-    pCsr->iOffset = x[0];
-    pCsr->szPage = (int)x[1];
-  }
-}
+  p = (sqlite3rbu*)sqlite3_malloc64(nByte);
+  if( p ){
+    RbuState *pState = 0;
 
-/*
-** Move a statvfs cursor to the next entry in the file.
-*/
-static int statNext(sqlite3_vtab_cursor *pCursor){
-  int rc;
-  int nPayload;
-  char *z;
-  StatCursor *pCsr = (StatCursor *)pCursor;
-  StatTable *pTab = (StatTable *)pCursor->pVtab;
-  Btree *pBt = pTab->db->aDb[pCsr->iDb].pBt;
-  Pager *pPager = sqlite3BtreePager(pBt);
+    /* Create the custom VFS. */
+    memset(p, 0, sizeof(sqlite3rbu));
+    rbuCreateVfs(p);
 
-  sqlite3_free(pCsr->zPath);
-  pCsr->zPath = 0;
+    /* Open the target, RBU and state databases */
+    if( p->rc==SQLITE_OK ){
+      char *pCsr = (char*)&p[1];
+      int bRetry = 0;
+      if( zTarget ){
+        p->zTarget = pCsr;
+        memcpy(p->zTarget, zTarget, nTarget+1);
+        pCsr += nTarget+1;
+      }
+      p->zRbu = pCsr;
+      memcpy(p->zRbu, zRbu, nRbu+1);
+      pCsr += nRbu+1;
+      if( zState ){
+        p->zState = rbuMPrintf(p, "%s", zState);
+      }
 
-statNextRestart:
-  if( pCsr->aPage[0].pPg==0 ){
-    rc = sqlite3_step(pCsr->pStmt);
-    if( rc==SQLITE_ROW ){
-      int nPage;
-      u32 iRoot = (u32)sqlite3_column_int64(pCsr->pStmt, 1);
-      sqlite3PagerPagecount(pPager, &nPage);
-      if( nPage==0 ){
-        pCsr->isEof = 1;
-        return sqlite3_reset(pCsr->pStmt);
+      /* If the first attempt to open the database file fails and the bRetry
+      ** flag it set, this means that the db was not opened because it seemed
+      ** to be a wal-mode db. But, this may have happened due to an earlier
+      ** RBU vacuum operation leaving an old wal file in the directory.
+      ** If this is the case, it will have been checkpointed and deleted
+      ** when the handle was closed and a second attempt to open the 
+      ** database may succeed.  */
+      rbuOpenDatabase(p, &bRetry);
+      if( bRetry ){
+        rbuOpenDatabase(p, 0);
       }
-      rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg, 0);
-      pCsr->aPage[0].iPgno = iRoot;
-      pCsr->aPage[0].iCell = 0;
-      pCsr->aPage[0].zPath = z = sqlite3_mprintf("/");
-      pCsr->iPage = 0;
-      if( z==0 ) rc = SQLITE_NOMEM_BKPT;
-    }else{
-      pCsr->isEof = 1;
-      return sqlite3_reset(pCsr->pStmt);
     }
-  }else{
 
-    /* Page p itself has already been visited. */
-    StatPage *p = &pCsr->aPage[pCsr->iPage];
+    if( p->rc==SQLITE_OK ){
+      pState = rbuLoadState(p);
+      assert( pState || p->rc!=SQLITE_OK );
+      if( p->rc==SQLITE_OK ){
 
-    while( p->iCell<p->nCell ){
-      StatCell *pCell = &p->aCell[p->iCell];
-      if( pCell->iOvfl<pCell->nOvfl ){
-        int nUsable;
-        sqlite3BtreeEnter(pBt);
-        nUsable = sqlite3BtreeGetPageSize(pBt) - 
-                        sqlite3BtreeGetReserveNoMutex(pBt);
-        sqlite3BtreeLeave(pBt);
-        pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
-        pCsr->iPageno = pCell->aOvfl[pCell->iOvfl];
-        pCsr->zPagetype = "overflow";
-        pCsr->nCell = 0;
-        pCsr->nMxPayload = 0;
-        pCsr->zPath = z = sqlite3_mprintf(
-            "%s%.3x+%.6x", p->zPath, p->iCell, pCell->iOvfl
-        );
-        if( pCell->iOvfl<pCell->nOvfl-1 ){
-          pCsr->nUnused = 0;
-          pCsr->nPayload = nUsable - 4;
+        if( pState->eStage==0 ){ 
+          rbuDeleteOalFile(p);
+          rbuInitPhaseOneSteps(p);
+          p->eStage = RBU_STAGE_OAL;
         }else{
-          pCsr->nPayload = pCell->nLastOvfl;
-          pCsr->nUnused = nUsable - 4 - pCsr->nPayload;
+          p->eStage = pState->eStage;
+          p->nPhaseOneStep = pState->nPhaseOneStep;
         }
-        pCell->iOvfl++;
-        statSizeAndOffset(pCsr);
-        return z==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK;
+        p->nProgress = pState->nProgress;
+        p->iOalSz = pState->iOalSz;
       }
-      if( p->iRightChildPg ) break;
-      p->iCell++;
-    }
-
-    if( !p->iRightChildPg || p->iCell>p->nCell ){
-      statClearPage(p);
-      if( pCsr->iPage==0 ) return statNext(pCursor);
-      pCsr->iPage--;
-      goto statNextRestart; /* Tail recursion */
     }
-    pCsr->iPage++;
-    assert( p==&pCsr->aPage[pCsr->iPage-1] );
+    assert( p->rc!=SQLITE_OK || p->eStage!=0 );
 
-    if( p->iCell==p->nCell ){
-      p[1].iPgno = p->iRightChildPg;
-    }else{
-      p[1].iPgno = p->aCell[p->iCell].iChildPg;
+    if( p->rc==SQLITE_OK && p->pTargetFd->pWalFd ){
+      if( p->eStage==RBU_STAGE_OAL ){
+        p->rc = SQLITE_ERROR;
+        p->zErrmsg = sqlite3_mprintf("cannot update wal mode database");
+      }else if( p->eStage==RBU_STAGE_MOVE ){
+        p->eStage = RBU_STAGE_CKPT;
+        p->nStep = 0;
+      }
     }
-    rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg, 0);
-    p[1].iCell = 0;
-    p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
-    p->iCell++;
-    if( z==0 ) rc = SQLITE_NOMEM_BKPT;
-  }
-
-
-  /* Populate the StatCursor fields with the values to be returned
-  ** by the xColumn() and xRowid() methods.
-  */
-  if( rc==SQLITE_OK ){
-    int i;
-    StatPage *p = &pCsr->aPage[pCsr->iPage];
-    pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
-    pCsr->iPageno = p->iPgno;
-
-    rc = statDecodePage(pBt, p);
-    if( rc==SQLITE_OK ){
-      statSizeAndOffset(pCsr);
 
-      switch( p->flags ){
-        case 0x05:             /* table internal */
-        case 0x02:             /* index internal */
-          pCsr->zPagetype = "internal";
-          break;
-        case 0x0D:             /* table leaf */
-        case 0x0A:             /* index leaf */
-          pCsr->zPagetype = "leaf";
-          break;
-        default:
-          pCsr->zPagetype = "corrupted";
-          break;
-      }
-      pCsr->nCell = p->nCell;
-      pCsr->nUnused = p->nUnused;
-      pCsr->nMxPayload = p->nMxPayload;
-      pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath);
-      if( z==0 ) rc = SQLITE_NOMEM_BKPT;
-      nPayload = 0;
-      for(i=0; i<p->nCell; i++){
-        nPayload += p->aCell[i].nLocal;
+    if( p->rc==SQLITE_OK 
+     && (p->eStage==RBU_STAGE_OAL || p->eStage==RBU_STAGE_MOVE)
+     && pState->eStage!=0
+    ){
+      rbu_file *pFd = (rbuIsVacuum(p) ? p->pRbuFd : p->pTargetFd);
+      if( pFd->iCookie!=pState->iCookie ){   
+        /* At this point (pTargetFd->iCookie) contains the value of the
+        ** change-counter cookie (the thing that gets incremented when a 
+        ** transaction is committed in rollback mode) currently stored on 
+        ** page 1 of the database file. */
+        p->rc = SQLITE_BUSY;
+        p->zErrmsg = sqlite3_mprintf("database modified during rbu %s",
+            (rbuIsVacuum(p) ? "vacuum" : "update")
+        );
       }
-      pCsr->nPayload = nPayload;
     }
-  }
 
-  return rc;
-}
+    if( p->rc==SQLITE_OK ){
+      if( p->eStage==RBU_STAGE_OAL ){
+        sqlite3 *db = p->dbMain;
+        p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, &p->zErrmsg);
 
-static int statEof(sqlite3_vtab_cursor *pCursor){
-  StatCursor *pCsr = (StatCursor *)pCursor;
-  return pCsr->isEof;
-}
+        /* Point the object iterator at the first object */
+        if( p->rc==SQLITE_OK ){
+          p->rc = rbuObjIterFirst(p, &p->objiter);
+        }
 
-static int statFilter(
-  sqlite3_vtab_cursor *pCursor, 
-  int idxNum, const char *idxStr,
-  int argc, sqlite3_value **argv
-){
-  StatCursor *pCsr = (StatCursor *)pCursor;
-  StatTable *pTab = (StatTable*)(pCursor->pVtab);
-  char *zSql;
-  int rc = SQLITE_OK;
-  char *zMaster;
+        /* If the RBU database contains no data_xxx tables, declare the RBU
+        ** update finished.  */
+        if( p->rc==SQLITE_OK && p->objiter.zTbl==0 ){
+          p->rc = SQLITE_DONE;
+          p->eStage = RBU_STAGE_DONE;
+        }else{
+          if( p->rc==SQLITE_OK && pState->eStage==0 && rbuIsVacuum(p) ){
+            rbuCopyPragma(p, "page_size");
+            rbuCopyPragma(p, "auto_vacuum");
+          }
 
-  if( idxNum==1 ){
-    const char *zDbase = (const char*)sqlite3_value_text(argv[0]);
-    pCsr->iDb = sqlite3FindDbName(pTab->db, zDbase);
-    if( pCsr->iDb<0 ){
-      sqlite3_free(pCursor->pVtab->zErrMsg);
-      pCursor->pVtab->zErrMsg = sqlite3_mprintf("no such schema: %s", zDbase);
-      return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM_BKPT;
-    }
-  }else{
-    pCsr->iDb = pTab->iDb;
-  }
-  statResetCsr(pCsr);
-  sqlite3_finalize(pCsr->pStmt);
-  pCsr->pStmt = 0;
-  zMaster = pCsr->iDb==1 ? "sqlite_temp_master" : "sqlite_master";
-  zSql = sqlite3_mprintf(
-      "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
-      "  UNION ALL  "
-      "SELECT name, rootpage, type"
-      "  FROM \"%w\".%s WHERE rootpage!=0"
-      "  ORDER BY name", pTab->db->aDb[pCsr->iDb].zDbSName, zMaster);
-  if( zSql==0 ){
-    return SQLITE_NOMEM_BKPT;
-  }else{
-    rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
-    sqlite3_free(zSql);
-  }
+          /* Open transactions both databases. The *-oal file is opened or
+          ** created at this point. */
+          if( p->rc==SQLITE_OK ){
+            p->rc = sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
+          }
 
-  if( rc==SQLITE_OK ){
-    rc = statNext(pCursor);
-  }
-  return rc;
-}
+          /* Check if the main database is a zipvfs db. If it is, set the upper
+          ** level pager to use "journal_mode=off". This prevents it from 
+          ** generating a large journal using a temp file.  */
+          if( p->rc==SQLITE_OK ){
+            int frc = sqlite3_file_control(db, "main", SQLITE_FCNTL_ZIPVFS, 0);
+            if( frc==SQLITE_OK ){
+              p->rc = sqlite3_exec(
+                db, "PRAGMA journal_mode=off",0,0,&p->zErrmsg);
+            }
+          }
 
-static int statColumn(
-  sqlite3_vtab_cursor *pCursor, 
-  sqlite3_context *ctx, 
-  int i
-){
-  StatCursor *pCsr = (StatCursor *)pCursor;
-  switch( i ){
-    case 0:            /* name */
-      sqlite3_result_text(ctx, pCsr->zName, -1, SQLITE_TRANSIENT);
-      break;
-    case 1:            /* path */
-      sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT);
-      break;
-    case 2:            /* pageno */
-      sqlite3_result_int64(ctx, pCsr->iPageno);
-      break;
-    case 3:            /* pagetype */
-      sqlite3_result_text(ctx, pCsr->zPagetype, -1, SQLITE_STATIC);
-      break;
-    case 4:            /* ncell */
-      sqlite3_result_int(ctx, pCsr->nCell);
-      break;
-    case 5:            /* payload */
-      sqlite3_result_int(ctx, pCsr->nPayload);
-      break;
-    case 6:            /* unused */
-      sqlite3_result_int(ctx, pCsr->nUnused);
-      break;
-    case 7:            /* mx_payload */
-      sqlite3_result_int(ctx, pCsr->nMxPayload);
-      break;
-    case 8:            /* pgoffset */
-      sqlite3_result_int64(ctx, pCsr->iOffset);
-      break;
-    case 9:            /* pgsize */
-      sqlite3_result_int(ctx, pCsr->szPage);
-      break;
-    default: {          /* schema */
-      sqlite3 *db = sqlite3_context_db_handle(ctx);
-      int iDb = pCsr->iDb;
-      sqlite3_result_text(ctx, db->aDb[iDb].zDbSName, -1, SQLITE_STATIC);
-      break;
+          if( p->rc==SQLITE_OK ){
+            rbuSetupOal(p, pState);
+          }
+        }
+      }else if( p->eStage==RBU_STAGE_MOVE ){
+        /* no-op */
+      }else if( p->eStage==RBU_STAGE_CKPT ){
+        rbuSetupCheckpoint(p, pState);
+      }else if( p->eStage==RBU_STAGE_DONE ){
+        p->rc = SQLITE_DONE;
+      }else{
+        p->rc = SQLITE_CORRUPT;
+      }
     }
-  }
-  return SQLITE_OK;
-}
-
-static int statRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
-  StatCursor *pCsr = (StatCursor *)pCursor;
-  *pRowid = pCsr->iPageno;
-  return SQLITE_OK;
-}
-
-/*
-** Invoke this routine to register the "dbstat" virtual table module
-*/
-SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){
-  static sqlite3_module dbstat_module = {
-    0,                            /* iVersion */
-    statConnect,                  /* xCreate */
-    statConnect,                  /* xConnect */
-    statBestIndex,                /* xBestIndex */
-    statDisconnect,               /* xDisconnect */
-    statDisconnect,               /* xDestroy */
-    statOpen,                     /* xOpen - open a cursor */
-    statClose,                    /* xClose - close a cursor */
-    statFilter,                   /* xFilter - configure scan constraints */
-    statNext,                     /* xNext - advance a cursor */
-    statEof,                      /* xEof - check for end of scan */
-    statColumn,                   /* xColumn - read data */
-    statRowid,                    /* xRowid - read data */
-    0,                            /* xUpdate */
-    0,                            /* xBegin */
-    0,                            /* xSync */
-    0,                            /* xCommit */
-    0,                            /* xRollback */
-    0,                            /* xFindMethod */
-    0,                            /* xRename */
-    0,                            /* xSavepoint */
-    0,                            /* xRelease */
-    0,                            /* xRollbackTo */
-  };
-  return sqlite3_create_module(db, "dbstat", &dbstat_module, 0);
-}
-#elif defined(SQLITE_ENABLE_DBSTAT_VTAB)
-SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; }
-#endif /* SQLITE_ENABLE_DBSTAT_VTAB */
-
-/************** End of dbstat.c **********************************************/
-/************** Begin file dbpage.c ******************************************/
-/*
-** 2017-10-11
-**
-** The author disclaims copyright to this source code.  In place of
-** a legal notice, here is a blessing:
-**
-**    May you do good and not evil.
-**    May you find forgiveness for yourself and forgive others.
-**    May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** This file contains an implementation of the "sqlite_dbpage" virtual table.
-**
-** The sqlite_dbpage virtual table is used to read or write whole raw
-** pages of the database file.  The pager interface is used so that 
-** uncommitted changes and changes recorded in the WAL file are correctly
-** retrieved.
-**
-** Usage example:
-**
-**    SELECT data FROM sqlite_dbpage('aux1') WHERE pgno=123;
-**
-** This is an eponymous virtual table so it does not need to be created before
-** use.  The optional argument to the sqlite_dbpage() table name is the
-** schema for the database file that is to be read.  The default schema is
-** "main".
-**
-** The data field of sqlite_dbpage table can be updated.  The new
-** value must be a BLOB which is the correct page size, otherwise the
-** update fails.  Rows may not be deleted or inserted.
-*/
-
-/* #include "sqliteInt.h"   ** Requires access to internal data structures ** */
-#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
-    && !defined(SQLITE_OMIT_VIRTUALTABLE)
-
-typedef struct DbpageTable DbpageTable;
-typedef struct DbpageCursor DbpageCursor;
-
-struct DbpageCursor {
-  sqlite3_vtab_cursor base;       /* Base class.  Must be first */
-  int pgno;                       /* Current page number */
-  int mxPgno;                     /* Last page to visit on this scan */
-  Pager *pPager;                  /* Pager being read/written */
-  DbPage *pPage1;                 /* Page 1 of the database */
-  int iDb;                        /* Index of database to analyze */
-  int szPage;                     /* Size of each page in bytes */
-};
-
-struct DbpageTable {
-  sqlite3_vtab base;              /* Base class.  Must be first */
-  sqlite3 *db;                    /* The database */
-};
-
-/* Columns */
-#define DBPAGE_COLUMN_PGNO    0
-#define DBPAGE_COLUMN_DATA    1
-#define DBPAGE_COLUMN_SCHEMA  2
-
-
-
-/*
-** Connect to or create a dbpagevfs virtual table.
-*/
-static int dbpageConnect(
-  sqlite3 *db,
-  void *pAux,
-  int argc, const char *const*argv,
-  sqlite3_vtab **ppVtab,
-  char **pzErr
-){
-  DbpageTable *pTab = 0;
-  int rc = SQLITE_OK;
-
-  rc = sqlite3_declare_vtab(db, 
-          "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
-  if( rc==SQLITE_OK ){
-    pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable));
-    if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
-  }
 
-  assert( rc==SQLITE_OK || pTab==0 );
-  if( rc==SQLITE_OK ){
-    memset(pTab, 0, sizeof(DbpageTable));
-    pTab->db = db;
+    rbuFreeState(pState);
   }
 
-  *ppVtab = (sqlite3_vtab*)pTab;
-  return rc;
-}
-
-/*
-** Disconnect from or destroy a dbpagevfs virtual table.
-*/
-static int dbpageDisconnect(sqlite3_vtab *pVtab){
-  sqlite3_free(pVtab);
-  return SQLITE_OK;
+  return p;
 }
 
 /*
-** idxNum:
-**
-**     0     schema=main, full table scan
-**     1     schema=main, pgno=?1
-**     2     schema=?1, full table scan
-**     3     schema=?1, pgno=?2
+** Allocate and return an RBU handle with all fields zeroed except for the
+** error code, which is set to SQLITE_MISUSE.
 */
-static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
-  int i;
-  int iPlan = 0;
-
-  /* If there is a schema= constraint, it must be honored.  Report a
-  ** ridiculously large estimated cost if the schema= constraint is
-  ** unavailable
-  */
-  for(i=0; i<pIdxInfo->nConstraint; i++){
-    struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
-    if( p->iColumn!=DBPAGE_COLUMN_SCHEMA ) continue;
-    if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
-    if( !p->usable ){
-      /* No solution.  Use the default SQLITE_BIG_DBL cost */
-      pIdxInfo->estimatedRows = 0x7fffffff;
-      return SQLITE_OK;
-    }
-    iPlan = 2;
-    pIdxInfo->aConstraintUsage[i].argvIndex = 1;
-    pIdxInfo->aConstraintUsage[i].omit = 1;
-    break;
-  }
-
-  /* If we reach this point, it means that either there is no schema=
-  ** constraint (in which case we use the "main" schema) or else the
-  ** schema constraint was accepted.  Lower the estimated cost accordingly
-  */
-  pIdxInfo->estimatedCost = 1.0e6;
-
-  /* Check for constraints against pgno */
-  for(i=0; i<pIdxInfo->nConstraint; i++){
-    struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
-    if( p->usable && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
-      pIdxInfo->estimatedRows = 1;
-      pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
-      pIdxInfo->estimatedCost = 1.0;
-      pIdxInfo->aConstraintUsage[i].argvIndex = iPlan ? 2 : 1;
-      pIdxInfo->aConstraintUsage[i].omit = 1;
-      iPlan |= 1;
-      break;
-    }
-  }
-  pIdxInfo->idxNum = iPlan;
-
-  if( pIdxInfo->nOrderBy>=1
-   && pIdxInfo->aOrderBy[0].iColumn<=0
-   && pIdxInfo->aOrderBy[0].desc==0
-  ){
-    pIdxInfo->orderByConsumed = 1;
+static sqlite3rbu *rbuMisuseError(void){
+  sqlite3rbu *pRet;
+  pRet = sqlite3_malloc64(sizeof(sqlite3rbu));
+  if( pRet ){
+    memset(pRet, 0, sizeof(sqlite3rbu));
+    pRet->rc = SQLITE_MISUSE;
   }
-  return SQLITE_OK;
+  return pRet;
 }
 
 /*
-** Open a new dbpagevfs cursor.
+** Open and return a new RBU handle. 
 */
-static int dbpageOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
-  DbpageCursor *pCsr;
-
-  pCsr = (DbpageCursor *)sqlite3_malloc64(sizeof(DbpageCursor));
-  if( pCsr==0 ){
-    return SQLITE_NOMEM_BKPT;
-  }else{
-    memset(pCsr, 0, sizeof(DbpageCursor));
-    pCsr->base.pVtab = pVTab;
-    pCsr->pgno = -1;
-  }
-
-  *ppCursor = (sqlite3_vtab_cursor *)pCsr;
-  return SQLITE_OK;
+SQLITE_API sqlite3rbu *sqlite3rbu_open(
+  const char *zTarget, 
+  const char *zRbu,
+  const char *zState
+){
+  if( zTarget==0 || zRbu==0 ){ return rbuMisuseError(); }
+  /* TODO: Check that zTarget and zRbu are non-NULL */
+  return openRbuHandle(zTarget, zRbu, zState);
 }
 
 /*
-** Close a dbpagevfs cursor.
+** Open a handle to begin or resume an RBU VACUUM operation.
 */
-static int dbpageClose(sqlite3_vtab_cursor *pCursor){
-  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
-  if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1);
-  sqlite3_free(pCsr);
-  return SQLITE_OK;
+SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
+  const char *zTarget, 
+  const char *zState
+){
+  if( zTarget==0 ){ return rbuMisuseError(); }
+  /* TODO: Check that both arguments are non-NULL */
+  return openRbuHandle(0, zTarget, zState);
 }
 
 /*
-** Move a dbpagevfs cursor to the next entry in the file.
+** Return the database handle used by pRbu.
 */
-static int dbpageNext(sqlite3_vtab_cursor *pCursor){
-  int rc = SQLITE_OK;
-  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
-  pCsr->pgno++;
-  return rc;
+SQLITE_API sqlite3 *sqlite3rbu_db(sqlite3rbu *pRbu, int bRbu){
+  sqlite3 *db = 0;
+  if( pRbu ){
+    db = (bRbu ? pRbu->dbRbu : pRbu->dbMain);
+  }
+  return db;
 }
 
-static int dbpageEof(sqlite3_vtab_cursor *pCursor){
-  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
-  return pCsr->pgno > pCsr->mxPgno;
-}
 
 /*
-** idxNum:
-**
-**     0     schema=main, full table scan
-**     1     schema=main, pgno=?1
-**     2     schema=?1, full table scan
-**     3     schema=?1, pgno=?2
-**
-** idxStr is not used
+** If the error code currently stored in the RBU handle is SQLITE_CONSTRAINT,
+** then edit any error message string so as to remove all occurrences of
+** the pattern "rbu_imp_[0-9]*".
 */
-static int dbpageFilter(
-  sqlite3_vtab_cursor *pCursor, 
-  int idxNum, const char *idxStr,
-  int argc, sqlite3_value **argv
-){
-  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
-  DbpageTable *pTab = (DbpageTable *)pCursor->pVtab;
-  int rc;
-  sqlite3 *db = pTab->db;
-  Btree *pBt;
-
-  /* Default setting is no rows of result */
-  pCsr->pgno = 1; 
-  pCsr->mxPgno = 0;
-
-  if( idxNum & 2 ){
-    const char *zSchema;
-    assert( argc>=1 );
-    zSchema = (const char*)sqlite3_value_text(argv[0]);
-    pCsr->iDb = sqlite3FindDbName(db, zSchema);
-    if( pCsr->iDb<0 ) return SQLITE_OK;
-  }else{
-    pCsr->iDb = 0;
-  }
-  pBt = db->aDb[pCsr->iDb].pBt;
-  if( pBt==0 ) return SQLITE_OK;
-  pCsr->pPager = sqlite3BtreePager(pBt);
-  pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
-  pCsr->mxPgno = sqlite3BtreeLastPage(pBt);
-  if( idxNum & 1 ){
-    assert( argc>(idxNum>>1) );
-    pCsr->pgno = sqlite3_value_int(argv[idxNum>>1]);
-    if( pCsr->pgno<1 || pCsr->pgno>pCsr->mxPgno ){
-      pCsr->pgno = 1;
-      pCsr->mxPgno = 0;
-    }else{
-      pCsr->mxPgno = pCsr->pgno;
+static void rbuEditErrmsg(sqlite3rbu *p){
+  if( p->rc==SQLITE_CONSTRAINT && p->zErrmsg ){
+    unsigned int i;
+    size_t nErrmsg = strlen(p->zErrmsg);
+    for(i=0; i<(nErrmsg-8); i++){
+      if( memcmp(&p->zErrmsg[i], "rbu_imp_", 8)==0 ){
+        int nDel = 8;
+        while( p->zErrmsg[i+nDel]>='0' && p->zErrmsg[i+nDel]<='9' ) nDel++;
+        memmove(&p->zErrmsg[i], &p->zErrmsg[i+nDel], nErrmsg + 1 - i - nDel);
+        nErrmsg -= nDel;
+      }
     }
-  }else{
-    assert( pCsr->pgno==1 );
   }
-  if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1);
-  rc = sqlite3PagerGet(pCsr->pPager, 1, &pCsr->pPage1, 0);
-  return rc;
 }
 
-static int dbpageColumn(
-  sqlite3_vtab_cursor *pCursor, 
-  sqlite3_context *ctx, 
-  int i
-){
-  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
-  int rc = SQLITE_OK;
-  switch( i ){
-    case 0: {           /* pgno */
-      sqlite3_result_int(ctx, pCsr->pgno);
-      break;
+/*
+** Close the RBU handle.
+*/
+SQLITE_API int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
+  int rc;
+  if( p ){
+
+    /* Commit the transaction to the *-oal file. */
+    if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_OAL ){
+      p->rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, &p->zErrmsg);
     }
-    case 1: {           /* data */
-      DbPage *pDbPage = 0;
-      rc = sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
-      if( rc==SQLITE_OK ){
-        sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pCsr->szPage,
-                            SQLITE_TRANSIENT);
-      }
-      sqlite3PagerUnref(pDbPage);
-      break;
+
+    /* Sync the db file if currently doing an incremental checkpoint */
+    if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_CKPT ){
+      sqlite3_file *pDb = p->pTargetFd->pReal;
+      p->rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
     }
-    default: {          /* schema */
-      sqlite3 *db = sqlite3_context_db_handle(ctx);
-      sqlite3_result_text(ctx, db->aDb[pCsr->iDb].zDbSName, -1, SQLITE_STATIC);
-      break;
+
+    rbuSaveState(p, p->eStage);
+
+    if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_OAL ){
+      p->rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, &p->zErrmsg);
     }
-  }
-  return SQLITE_OK;
-}
 
-static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
-  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
-  *pRowid = pCsr->pgno;
-  return SQLITE_OK;
-}
+    /* Close any open statement handles. */
+    rbuObjIterFinalize(&p->objiter);
 
-static int dbpageUpdate(
-  sqlite3_vtab *pVtab,
-  int argc,
-  sqlite3_value **argv,
-  sqlite_int64 *pRowid
-){
-  DbpageTable *pTab = (DbpageTable *)pVtab;
-  Pgno pgno;
-  DbPage *pDbPage = 0;
-  int rc = SQLITE_OK;
-  char *zErr = 0;
-  const char *zSchema;
-  int iDb;
-  Btree *pBt;
-  Pager *pPager;
-  int szPage;
+    /* If this is an RBU vacuum handle and the vacuum has either finished
+    ** successfully or encountered an error, delete the contents of the 
+    ** state table. This causes the next call to sqlite3rbu_vacuum() 
+    ** specifying the current target and state databases to start a new
+    ** vacuum from scratch.  */
+    if( rbuIsVacuum(p) && p->rc!=SQLITE_OK && p->dbRbu ){
+      int rc2 = sqlite3_exec(p->dbRbu, "DELETE FROM stat.rbu_state", 0, 0, 0);
+      if( p->rc==SQLITE_DONE && rc2!=SQLITE_OK ) p->rc = rc2;
+    }
 
-  if( argc==1 ){
-    zErr = "cannot delete";
-    goto update_fail;
-  }
-  pgno = sqlite3_value_int(argv[0]);
-  if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){
-    zErr = "cannot insert";
-    goto update_fail;
-  }
-  zSchema = (const char*)sqlite3_value_text(argv[4]);
-  iDb = zSchema ? sqlite3FindDbName(pTab->db, zSchema) : -1;
-  if( iDb<0 ){
-    zErr = "no such schema";
-    goto update_fail;
-  }
-  pBt = pTab->db->aDb[iDb].pBt;
-  if( pgno<1 || pBt==0 || pgno>(int)sqlite3BtreeLastPage(pBt) ){
-    zErr = "bad page number";
-    goto update_fail;
-  }
-  szPage = sqlite3BtreeGetPageSize(pBt);
-  if( sqlite3_value_type(argv[3])!=SQLITE_BLOB 
-   || sqlite3_value_bytes(argv[3])!=szPage
-  ){
-    zErr = "bad page value";
-    goto update_fail;
-  }
-  pPager = sqlite3BtreePager(pBt);
-  rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0);
-  if( rc==SQLITE_OK ){
-    rc = sqlite3PagerWrite(pDbPage);
-    if( rc==SQLITE_OK ){
-      memcpy(sqlite3PagerGetData(pDbPage),
-             sqlite3_value_blob(argv[3]),
-             szPage);
+    /* Close the open database handle and VFS object. */
+    sqlite3_close(p->dbRbu);
+    sqlite3_close(p->dbMain);
+    assert( p->szTemp==0 );
+    rbuDeleteVfs(p);
+    sqlite3_free(p->aBuf);
+    sqlite3_free(p->aFrame);
+
+    rbuEditErrmsg(p);
+    rc = p->rc;
+    if( pzErrmsg ){
+      *pzErrmsg = p->zErrmsg;
+    }else{
+      sqlite3_free(p->zErrmsg);
     }
+    sqlite3_free(p->zState);
+    sqlite3_free(p);
+  }else{
+    rc = SQLITE_NOMEM;
+    *pzErrmsg = 0;
   }
-  sqlite3PagerUnref(pDbPage);
   return rc;
-
-update_fail:
-  sqlite3_free(pVtab->zErrMsg);
-  pVtab->zErrMsg = sqlite3_mprintf("%s", zErr);
-  return SQLITE_ERROR;
 }
 
-/* Since we do not know in advance which database files will be
-** written by the sqlite_dbpage virtual table, start a write transaction
-** on them all.
+/*
+** 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.
 */
-static int dbpageBegin(sqlite3_vtab *pVtab){
-  DbpageTable *pTab = (DbpageTable *)pVtab;
-  sqlite3 *db = pTab->db;
-  int i;
-  for(i=0; i<db->nDb; i++){
-    Btree *pBt = db->aDb[i].pBt;
-    if( pBt ) sqlite3BtreeBeginTrans(pBt, 1);
-  }
-  return SQLITE_OK;
+SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu){
+  return pRbu->nProgress;
 }
 
-
 /*
-** Invoke this routine to register the "dbpage" virtual table module
+** Return permyriadage progress indications for the two main stages of
+** an RBU update.
 */
-SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){
-  static sqlite3_module dbpage_module = {
-    0,                            /* iVersion */
-    dbpageConnect,                /* xCreate */
-    dbpageConnect,                /* xConnect */
-    dbpageBestIndex,              /* xBestIndex */
-    dbpageDisconnect,             /* xDisconnect */
-    dbpageDisconnect,             /* xDestroy */
-    dbpageOpen,                   /* xOpen - open a cursor */
-    dbpageClose,                  /* xClose - close a cursor */
-    dbpageFilter,                 /* xFilter - configure scan constraints */
-    dbpageNext,                   /* xNext - advance a cursor */
-    dbpageEof,                    /* xEof - check for end of scan */
-    dbpageColumn,                 /* xColumn - read data */
-    dbpageRowid,                  /* xRowid - read data */
-    dbpageUpdate,                 /* xUpdate */
-    dbpageBegin,                  /* xBegin */
-    0,                            /* xSync */
-    0,                            /* xCommit */
-    0,                            /* xRollback */
-    0,                            /* xFindMethod */
-    0,                            /* xRename */
-    0,                            /* xSavepoint */
-    0,                            /* xRelease */
-    0,                            /* xRollbackTo */
-  };
-  return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
-}
-#elif defined(SQLITE_ENABLE_DBPAGE_VTAB)
-SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; }
-#endif /* SQLITE_ENABLE_DBSTAT_VTAB */
+SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *p, int *pnOne, int *pnTwo){
+  const int MAX_PROGRESS = 10000;
+  switch( p->eStage ){
+    case RBU_STAGE_OAL:
+      if( p->nPhaseOneStep>0 ){
+        *pnOne = (int)(MAX_PROGRESS * (i64)p->nProgress/(i64)p->nPhaseOneStep);
+      }else{
+        *pnOne = -1;
+      }
+      *pnTwo = 0;
+      break;
 
-/************** End of dbpage.c **********************************************/
-/************** Begin file sqlite3session.c **********************************/
+    case RBU_STAGE_MOVE:
+      *pnOne = MAX_PROGRESS;
+      *pnTwo = 0;
+      break;
 
-#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
-/* #include "sqlite3session.h" */
-/* #include <assert.h> */
-/* #include <string.h> */
+    case RBU_STAGE_CKPT:
+      *pnOne = MAX_PROGRESS;
+      *pnTwo = (int)(MAX_PROGRESS * (i64)p->nStep / (i64)p->nFrame);
+      break;
 
-#ifndef SQLITE_AMALGAMATION
-/* # include "sqliteInt.h" */
-/* # include "vdbeInt.h" */
-#endif
+    case RBU_STAGE_DONE:
+      *pnOne = MAX_PROGRESS;
+      *pnTwo = MAX_PROGRESS;
+      break;
 
-typedef struct SessionTable SessionTable;
-typedef struct SessionChange SessionChange;
-typedef struct SessionBuffer SessionBuffer;
-typedef struct SessionInput SessionInput;
+    default:
+      assert( 0 );
+  }
+}
 
 /*
-** Minimum chunk size used by streaming versions of functions.
+** Return the current state of the RBU vacuum or update operation.
 */
-#ifndef SESSIONS_STRM_CHUNK_SIZE
-# ifdef SQLITE_TEST
-#   define SESSIONS_STRM_CHUNK_SIZE 64
-# else
-#   define SESSIONS_STRM_CHUNK_SIZE 1024
-# endif
-#endif
+SQLITE_API int sqlite3rbu_state(sqlite3rbu *p){
+  int aRes[] = {
+    0, SQLITE_RBU_STATE_OAL, SQLITE_RBU_STATE_MOVE,
+    0, SQLITE_RBU_STATE_CHECKPOINT, SQLITE_RBU_STATE_DONE
+  };
 
-typedef struct SessionHook SessionHook;
-struct SessionHook {
-  void *pCtx;
-  int (*xOld)(void*,int,sqlite3_value**);
-  int (*xNew)(void*,int,sqlite3_value**);
-  int (*xCount)(void*);
-  int (*xDepth)(void*);
-};
+  assert( RBU_STAGE_OAL==1 );
+  assert( RBU_STAGE_MOVE==2 );
+  assert( RBU_STAGE_CKPT==4 );
+  assert( RBU_STAGE_DONE==5 );
+  assert( aRes[RBU_STAGE_OAL]==SQLITE_RBU_STATE_OAL );
+  assert( aRes[RBU_STAGE_MOVE]==SQLITE_RBU_STATE_MOVE );
+  assert( aRes[RBU_STAGE_CKPT]==SQLITE_RBU_STATE_CHECKPOINT );
+  assert( aRes[RBU_STAGE_DONE]==SQLITE_RBU_STATE_DONE );
 
-/*
-** Session handle structure.
-*/
-struct sqlite3_session {
-  sqlite3 *db;                    /* Database handle session is attached to */
-  char *zDb;                      /* Name of database session is attached to */
-  int bEnable;                    /* True if currently recording */
-  int bIndirect;                  /* True if all changes are indirect */
-  int bAutoAttach;                /* True to auto-attach tables */
-  int rc;                         /* Non-zero if an error has occurred */
-  void *pFilterCtx;               /* First argument to pass to xTableFilter */
-  int (*xTableFilter)(void *pCtx, const char *zTab);
-  sqlite3_value *pZeroBlob;       /* Value containing X'' */
-  sqlite3_session *pNext;         /* Next session object on same db. */
-  SessionTable *pTable;           /* List of attached tables */
-  SessionHook hook;               /* APIs to grab new and old data with */
-};
+  if( p->rc!=SQLITE_OK && p->rc!=SQLITE_DONE ){
+    return SQLITE_RBU_STATE_ERROR;
+  }else{
+    assert( p->rc!=SQLITE_DONE || p->eStage==RBU_STAGE_DONE );
+    assert( p->eStage==RBU_STAGE_OAL
+         || p->eStage==RBU_STAGE_MOVE
+         || p->eStage==RBU_STAGE_CKPT
+         || p->eStage==RBU_STAGE_DONE
+    );
+    return aRes[p->eStage];
+  }
+}
 
-/*
-** Instances of this structure are used to build strings or binary records.
-*/
-struct SessionBuffer {
-  u8 *aBuf;                       /* Pointer to changeset buffer */
-  int nBuf;                       /* Size of buffer aBuf */
-  int nAlloc;                     /* Size of allocation containing aBuf */
-};
+SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){
+  int rc = p->rc;
+  if( rc==SQLITE_DONE ) return SQLITE_OK;
 
-/*
-** An object of this type is used internally as an abstraction for 
-** input data. Input data may be supplied either as a single large buffer
-** (e.g. sqlite3changeset_start()) or using a stream function (e.g.
-**  sqlite3changeset_start_strm()).
-*/
-struct SessionInput {
-  int bNoDiscard;                 /* If true, do not discard in InputBuffer() */
-  int iCurrent;                   /* Offset in aData[] of current change */
-  int iNext;                      /* Offset in aData[] of next change */
-  u8 *aData;                      /* Pointer to buffer containing changeset */
-  int nData;                      /* Number of bytes in aData */
+  assert( p->eStage>=RBU_STAGE_OAL && p->eStage<=RBU_STAGE_DONE );
+  if( p->eStage==RBU_STAGE_OAL ){
+    assert( rc!=SQLITE_DONE );
+    if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, 0);
+  }
 
-  SessionBuffer buf;              /* Current read buffer */
-  int (*xInput)(void*, void*, int*);        /* Input stream call (or NULL) */
-  void *pIn;                                /* First argument to xInput */
-  int bEof;                       /* Set to true after xInput finished */
-};
+  /* Sync the db file */
+  if( rc==SQLITE_OK && p->eStage==RBU_STAGE_CKPT ){
+    sqlite3_file *pDb = p->pTargetFd->pReal;
+    rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
+  }
 
-/*
-** Structure for changeset iterators.
-*/
-struct sqlite3_changeset_iter {
-  SessionInput in;                /* Input buffer or stream */
-  SessionBuffer tblhdr;           /* Buffer to hold apValue/zTab/abPK/ */
-  int bPatchset;                  /* True if this is a patchset */
-  int rc;                         /* Iterator error code */
-  sqlite3_stmt *pConflict;        /* Points to conflicting row, if any */
-  char *zTab;                     /* Current table */
-  int nCol;                       /* Number of columns in zTab */
-  int op;                         /* Current operation */
-  int bIndirect;                  /* True if current change was indirect */
-  u8 *abPK;                       /* Primary key array */
-  sqlite3_value **apValue;        /* old.* and new.* values */
-};
+  p->rc = rc;
+  rbuSaveState(p, p->eStage);
+  rc = p->rc;
 
-/*
-** Each session object maintains a set of the following structures, one
-** for each table the session object is monitoring. The structures are
-** stored in a linked list starting at sqlite3_session.pTable.
-**
-** The keys of the SessionTable.aChange[] hash table are all rows that have
-** been modified in any way since the session object was attached to the
-** table.
-**
-** The data associated with each hash-table entry is a structure containing
-** a subset of the initial values that the modified row contained at the
-** start of the session. Or no initial values if the row was inserted.
-*/
-struct SessionTable {
-  SessionTable *pNext;
-  char *zName;                    /* Local name of table */
-  int nCol;                       /* Number of columns in table zName */
-  int bStat1;                     /* True if this is sqlite_stat1 */
-  const char **azCol;             /* Column names */
-  u8 *abPK;                       /* Array of primary key flags */
-  int nEntry;                     /* Total number of entries in hash table */
-  int nChange;                    /* Size of apChange[] array */
-  SessionChange **apChange;       /* Hash table buckets */
-};
+  if( p->eStage==RBU_STAGE_OAL ){
+    assert( rc!=SQLITE_DONE );
+    if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0);
+    if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbRbu, "BEGIN IMMEDIATE", 0, 0, 0);
+    if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "BEGIN IMMEDIATE", 0, 0,0);
+  }
 
-/* 
-** RECORD FORMAT:
-**
-** The following record format is similar to (but not compatible with) that 
-** used in SQLite database files. This format is used as part of the 
-** change-set binary format, and so must be architecture independent.
-**
-** Unlike the SQLite database record format, each field is self-contained -
-** there is no separation of header and data. Each field begins with a
-** single byte describing its type, as follows:
-**
-**       0x00: Undefined value.
-**       0x01: Integer value.
-**       0x02: Real value.
-**       0x03: Text value.
-**       0x04: Blob value.
-**       0x05: SQL NULL value.
-**
-** Note that the above match the definitions of SQLITE_INTEGER, SQLITE_TEXT
-** and so on in sqlite3.h. For undefined and NULL values, the field consists
-** only of the single type byte. For other types of values, the type byte
-** is followed by:
-**
-**   Text values:
-**     A varint containing the number of bytes in the value (encoded using
-**     UTF-8). Followed by a buffer containing the UTF-8 representation
-**     of the text value. There is no nul terminator.
-**
-**   Blob values:
-**     A varint containing the number of bytes in the value, followed by
-**     a buffer containing the value itself.
-**
-**   Integer values:
-**     An 8-byte big-endian integer value.
-**
-**   Real values:
-**     An 8-byte big-endian IEEE 754-2008 real value.
-**
-** Varint values are encoded in the same way as varints in the SQLite 
-** record format.
-**
-** CHANGESET FORMAT:
-**
-** A changeset is a collection of DELETE, UPDATE and INSERT operations on
-** one or more tables. Operations on a single table are grouped together,
-** but may occur in any order (i.e. deletes, updates and inserts are all
-** mixed together).
-**
-** Each group of changes begins with a table header:
-**
-**   1 byte: Constant 0x54 (capital 'T')
-**   Varint: Number of columns in the table.
-**   nCol bytes: 0x01 for PK columns, 0x00 otherwise.
-**   N bytes: Unqualified table name (encoded using UTF-8). Nul-terminated.
-**
-** Followed by one or more changes to the table.
-**
-**   1 byte: Either SQLITE_INSERT (0x12), UPDATE (0x17) or DELETE (0x09).
-**   1 byte: The "indirect-change" flag.
-**   old.* record: (delete and update only)
-**   new.* record: (insert and update only)
-**
-** The "old.*" and "new.*" records, if present, are N field records in the
-** format described above under "RECORD FORMAT", where N is the number of
-** columns in the table. The i'th field of each record is associated with
-** the i'th column of the table, counting from left to right in the order
-** in which columns were declared in the CREATE TABLE statement.
-**
-** The new.* record that is part of each INSERT change contains the values
-** that make up the new row. Similarly, the old.* record that is part of each
-** DELETE change contains the values that made up the row that was deleted 
-** from the database. In the changeset format, the records that are part
-** of INSERT or DELETE changes never contain any undefined (type byte 0x00)
-** fields.
-**
-** Within the old.* record associated with an UPDATE change, all fields
-** associated with table columns that are not PRIMARY KEY columns and are
-** not modified by the UPDATE change are set to "undefined". Other fields
-** are set to the values that made up the row before the UPDATE that the
-** change records took place. Within the new.* record, fields associated 
-** with table columns modified by the UPDATE change contain the new 
-** values. Fields associated with table columns that are not modified
-** are set to "undefined".
+  p->rc = rc;
+  return rc;
+}
+
+/**************************************************************************
+** Beginning of RBU VFS shim methods. The VFS shim modifies the behaviour
+** of a standard VFS in the following ways:
 **
-** PATCHSET FORMAT:
+** 1. Whenever the first page of a main database file is read or 
+**    written, the value of the change-counter cookie is stored in
+**    rbu_file.iCookie. Similarly, the value of the "write-version"
+**    database header field is stored in rbu_file.iWriteVer. This ensures
+**    that the values are always trustworthy within an open transaction.
 **
-** A patchset is also a collection of changes. It is similar to a changeset,
-** but leaves undefined those fields that are not useful if no conflict
-** resolution is required when applying the changeset.
+** 2. Whenever an SQLITE_OPEN_WAL file is opened, the (rbu_file.pWalFd)
+**    member variable of the associated database file descriptor is set
+**    to point to the new file. A mutex protected linked list of all main 
+**    db fds opened using a particular RBU VFS is maintained at 
+**    rbu_vfs.pMain to facilitate this.
 **
-** Each group of changes begins with a table header:
+** 3. Using a new file-control "SQLITE_FCNTL_RBU", a main db rbu_file 
+**    object can be marked as the target database of an RBU update. This
+**    turns on the following extra special behaviour:
 **
-**   1 byte: Constant 0x50 (capital 'P')
-**   Varint: Number of columns in the table.
-**   nCol bytes: 0x01 for PK columns, 0x00 otherwise.
-**   N bytes: Unqualified table name (encoded using UTF-8). Nul-terminated.
+** 3a. If xAccess() is called to check if there exists a *-wal file 
+**     associated with an RBU target database currently in RBU_STAGE_OAL
+**     stage (preparing the *-oal file), the following special handling
+**     applies:
 **
-** Followed by one or more changes to the table.
+**      * if the *-wal file does exist, return SQLITE_CANTOPEN. An RBU
+**        target database may not be in wal mode already.
 **
-**   1 byte: Either SQLITE_INSERT (0x12), UPDATE (0x17) or DELETE (0x09).
-**   1 byte: The "indirect-change" flag.
-**   single record: (PK fields for DELETE, PK and modified fields for UPDATE,
-**                   full record for INSERT).
+**      * if the *-wal file does not exist, set the output parameter to
+**        non-zero (to tell SQLite that it does exist) anyway.
 **
-** As in the changeset format, each field of the single record that is part
-** of a patchset change is associated with the correspondingly positioned
-** table column, counting from left to right within the CREATE TABLE 
-** statement.
+**     Then, when xOpen() is called to open the *-wal file associated with
+**     the RBU target in RBU_STAGE_OAL stage, instead of opening the *-wal
+**     file, the rbu vfs opens the corresponding *-oal file instead. 
 **
-** For a DELETE change, all fields within the record except those associated
-** with PRIMARY KEY columns are omitted. The PRIMARY KEY fields contain the
-** values identifying the row to delete.
+** 3b. The *-shm pages returned by xShmMap() for a target db file in
+**     RBU_STAGE_OAL mode are actually stored in heap memory. This is to
+**     avoid creating a *-shm file on disk. Additionally, xShmLock() calls
+**     are no-ops on target database files in RBU_STAGE_OAL mode. This is
+**     because assert() statements in some VFS implementations fail if 
+**     xShmLock() is called before xShmMap().
 **
-** For an UPDATE change, all fields except those associated with PRIMARY KEY
-** columns and columns that are modified by the UPDATE are set to "undefined".
-** PRIMARY KEY fields contain the values identifying the table row to update,
-** and fields associated with modified columns contain the new column values.
+** 3c. If an EXCLUSIVE lock is attempted on a target database file in any
+**     mode except RBU_STAGE_DONE (all work completed and checkpointed), it 
+**     fails with an SQLITE_BUSY error. This is to stop RBU connections
+**     from automatically checkpointing a *-wal (or *-oal) file from within
+**     sqlite3_close().
 **
-** The records associated with INSERT changes are in the same format as for
-** changesets. It is not possible for a record associated with an INSERT
-** change to contain a field set to "undefined".
-*/
-
-/*
-** For each row modified during a session, there exists a single instance of
-** this structure stored in a SessionTable.aChange[] hash table.
+** 3d. In RBU_STAGE_CAPTURE mode, all xRead() calls on the wal file, and
+**     all xWrite() calls on the target database file perform no IO. 
+**     Instead the frame and page numbers that would be read and written
+**     are recorded. Additionally, successful attempts to obtain exclusive
+**     xShmLock() WRITER, CHECKPOINTER and READ0 locks on the target 
+**     database file are recorded. xShmLock() calls to unlock the same
+**     locks are no-ops (so that once obtained, these locks are never
+**     relinquished). Finally, calls to xSync() on the target database
+**     file fail with SQLITE_INTERNAL errors.
 */
-struct SessionChange {
-  int op;                         /* One of UPDATE, DELETE, INSERT */
-  int bIndirect;                  /* True if this change is "indirect" */
-  int nRecord;                    /* Number of bytes in buffer aRecord[] */
-  u8 *aRecord;                    /* Buffer containing old.* record */
-  SessionChange *pNext;           /* For hash-table collisions */
-};
 
-/*
-** Write a varint with value iVal into the buffer at aBuf. Return the 
-** number of bytes written.
-*/
-static int sessionVarintPut(u8 *aBuf, int iVal){
-  return putVarint32(aBuf, iVal);
+static void rbuUnlockShm(rbu_file *p){
+  assert( p->openFlags & SQLITE_OPEN_MAIN_DB );
+  if( p->pRbu ){
+    int (*xShmLock)(sqlite3_file*,int,int,int) = p->pReal->pMethods->xShmLock;
+    int i;
+    for(i=0; i<SQLITE_SHM_NLOCK;i++){
+      if( (1<<i) & p->pRbu->mLock ){
+        xShmLock(p->pReal, i, 1, SQLITE_SHM_UNLOCK|SQLITE_SHM_EXCLUSIVE);
+      }
+    }
+    p->pRbu->mLock = 0;
+  }
 }
 
 /*
-** Return the number of bytes required to store value iVal as a varint.
 */
-static int sessionVarintLen(int iVal){
-  return sqlite3VarintLen(iVal);
+static int rbuUpdateTempSize(rbu_file *pFd, sqlite3_int64 nNew){
+  sqlite3rbu *pRbu = pFd->pRbu;
+  i64 nDiff = nNew - pFd->sz;
+  pRbu->szTemp += nDiff;
+  pFd->sz = nNew;
+  assert( pRbu->szTemp>=0 );
+  if( pRbu->szTempLimit && pRbu->szTemp>pRbu->szTempLimit ) return SQLITE_FULL;
+  return SQLITE_OK;
 }
 
 /*
-** Read a varint value from aBuf[] into *piVal. Return the number of 
-** bytes read.
+** Close an rbu file.
 */
-static int sessionVarintGet(u8 *aBuf, int *piVal){
-  return getVarint32(aBuf, *piVal);
+static int rbuVfsClose(sqlite3_file *pFile){
+  rbu_file *p = (rbu_file*)pFile;
+  int rc;
+  int i;
+
+  /* Free the contents of the apShm[] array. And the array itself. */
+  for(i=0; i<p->nShm; i++){
+    sqlite3_free(p->apShm[i]);
+  }
+  sqlite3_free(p->apShm);
+  p->apShm = 0;
+  sqlite3_free(p->zDel);
+
+  if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
+    rbu_file **pp;
+    sqlite3_mutex_enter(p->pRbuVfs->mutex);
+    for(pp=&p->pRbuVfs->pMain; *pp!=p; pp=&((*pp)->pMainNext));
+    *pp = p->pMainNext;
+    sqlite3_mutex_leave(p->pRbuVfs->mutex);
+    rbuUnlockShm(p);
+    p->pReal->pMethods->xShmUnmap(p->pReal, 0);
+  }
+  else if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){
+    rbuUpdateTempSize(p, 0);
+  }
+
+  /* Close the underlying file handle */
+  rc = p->pReal->pMethods->xClose(p->pReal);
+  return rc;
 }
 
-/* Load an unaligned and unsigned 32-bit integer */
-#define SESSION_UINT32(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3])
 
 /*
-** Read a 64-bit big-endian integer value from buffer aRec[]. Return
-** the value read.
+** Read and return an unsigned 32-bit big-endian integer from the buffer 
+** passed as the only argument.
 */
-static sqlite3_int64 sessionGetI64(u8 *aRec){
-  u64 x = SESSION_UINT32(aRec);
-  u32 y = SESSION_UINT32(aRec+4);
-  x = (x<<32) + y;
-  return (sqlite3_int64)x;
+static u32 rbuGetU32(u8 *aBuf){
+  return ((u32)aBuf[0] << 24)
+       + ((u32)aBuf[1] << 16)
+       + ((u32)aBuf[2] <<  8)
+       + ((u32)aBuf[3]);
 }
 
 /*
-** Write a 64-bit big-endian integer value to the buffer aBuf[].
+** Write an unsigned 32-bit value in big-endian format to the supplied
+** buffer.
 */
-static void sessionPutI64(u8 *aBuf, sqlite3_int64 i){
-  aBuf[0] = (i>>56) & 0xFF;
-  aBuf[1] = (i>>48) & 0xFF;
-  aBuf[2] = (i>>40) & 0xFF;
-  aBuf[3] = (i>>32) & 0xFF;
-  aBuf[4] = (i>>24) & 0xFF;
-  aBuf[5] = (i>>16) & 0xFF;
-  aBuf[6] = (i>> 8) & 0xFF;
-  aBuf[7] = (i>> 0) & 0xFF;
+static void rbuPutU32(u8 *aBuf, u32 iVal){
+  aBuf[0] = (iVal >> 24) & 0xFF;
+  aBuf[1] = (iVal >> 16) & 0xFF;
+  aBuf[2] = (iVal >>  8) & 0xFF;
+  aBuf[3] = (iVal >>  0) & 0xFF;
+}
+
+static void rbuPutU16(u8 *aBuf, u16 iVal){
+  aBuf[0] = (iVal >>  8) & 0xFF;
+  aBuf[1] = (iVal >>  0) & 0xFF;
 }
 
 /*
-** This function is used to serialize the contents of value pValue (see
-** comment titled "RECORD FORMAT" above).
-**
-** If it is non-NULL, the serialized form of the value is written to 
-** buffer aBuf. *pnWrite is set to the number of bytes written before
-** returning. Or, if aBuf is NULL, the only thing this function does is
-** set *pnWrite.
-**
-** If no error occurs, SQLITE_OK is returned. Or, if an OOM error occurs
-** within a call to sqlite3_value_text() (may fail if the db is utf-16)) 
-** SQLITE_NOMEM is returned.
+** Read data from an rbuVfs-file.
 */
-static int sessionSerializeValue(
-  u8 *aBuf,                       /* If non-NULL, write serialized value here */
-  sqlite3_value *pValue,          /* Value to serialize */
-  int *pnWrite                    /* IN/OUT: Increment by bytes written */
+static int rbuVfsRead(
+  sqlite3_file *pFile, 
+  void *zBuf, 
+  int iAmt, 
+  sqlite_int64 iOfst
 ){
-  int nByte;                      /* Size of serialized value in bytes */
+  rbu_file *p = (rbu_file*)pFile;
+  sqlite3rbu *pRbu = p->pRbu;
+  int rc;
 
-  if( pValue ){
-    int eType;                    /* Value type (SQLITE_NULL, TEXT etc.) */
-  
-    eType = sqlite3_value_type(pValue);
-    if( aBuf ) aBuf[0] = eType;
-  
-    switch( eType ){
-      case SQLITE_NULL: 
-        nByte = 1;
-        break;
-  
-      case SQLITE_INTEGER: 
-      case SQLITE_FLOAT:
-        if( aBuf ){
-          /* TODO: SQLite does something special to deal with mixed-endian
-          ** floating point values (e.g. ARM7). This code probably should
-          ** too.  */
-          u64 i;
-          if( eType==SQLITE_INTEGER ){
-            i = (u64)sqlite3_value_int64(pValue);
-          }else{
-            double r;
-            assert( sizeof(double)==8 && sizeof(u64)==8 );
-            r = sqlite3_value_double(pValue);
-            memcpy(&i, &r, 8);
+  if( pRbu && pRbu->eStage==RBU_STAGE_CAPTURE ){
+    assert( p->openFlags & SQLITE_OPEN_WAL );
+    rc = rbuCaptureWalRead(p->pRbu, iOfst, iAmt);
+  }else{
+    if( pRbu && pRbu->eStage==RBU_STAGE_OAL 
+     && (p->openFlags & SQLITE_OPEN_WAL) 
+     && iOfst>=pRbu->iOalSz 
+    ){
+      rc = SQLITE_OK;
+      memset(zBuf, 0, iAmt);
+    }else{
+      rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
+#if 1
+      /* If this is being called to read the first page of the target 
+      ** database as part of an rbu vacuum operation, synthesize the 
+      ** contents of the first page if it does not yet exist. Otherwise,
+      ** SQLite will not check for a *-wal file.  */
+      if( pRbu && rbuIsVacuum(pRbu) 
+          && rc==SQLITE_IOERR_SHORT_READ && iOfst==0
+          && (p->openFlags & SQLITE_OPEN_MAIN_DB)
+          && pRbu->rc==SQLITE_OK
+      ){
+        sqlite3_file *pFd = (sqlite3_file*)pRbu->pRbuFd;
+        rc = pFd->pMethods->xRead(pFd, zBuf, iAmt, iOfst);
+        if( rc==SQLITE_OK ){
+          u8 *aBuf = (u8*)zBuf;
+          u32 iRoot = rbuGetU32(&aBuf[52]) ? 1 : 0;
+          rbuPutU32(&aBuf[52], iRoot);      /* largest root page number */
+          rbuPutU32(&aBuf[36], 0);          /* number of free pages */
+          rbuPutU32(&aBuf[32], 0);          /* first page on free list trunk */
+          rbuPutU32(&aBuf[28], 1);          /* size of db file in pages */
+          rbuPutU32(&aBuf[24], pRbu->pRbuFd->iCookie+1);  /* Change counter */
+
+          if( iAmt>100 ){
+            memset(&aBuf[100], 0, iAmt-100);
+            rbuPutU16(&aBuf[105], iAmt & 0xFFFF);
+            aBuf[100] = 0x0D;
           }
-          sessionPutI64(&aBuf[1], i);
-        }
-        nByte = 9; 
-        break;
-  
-      default: {
-        u8 *z;
-        int n;
-        int nVarint;
-  
-        assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
-        if( eType==SQLITE_TEXT ){
-          z = (u8 *)sqlite3_value_text(pValue);
-        }else{
-          z = (u8 *)sqlite3_value_blob(pValue);
-        }
-        n = sqlite3_value_bytes(pValue);
-        if( z==0 && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
-        nVarint = sessionVarintLen(n);
-  
-        if( aBuf ){
-          sessionVarintPut(&aBuf[1], n);
-          if( n ) memcpy(&aBuf[nVarint + 1], z, n);
         }
-  
-        nByte = 1 + nVarint + n;
-        break;
       }
+#endif
+    }
+    if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
+      /* These look like magic numbers. But they are stable, as they are part
+       ** of the definition of the SQLite file format, which may not change. */
+      u8 *pBuf = (u8*)zBuf;
+      p->iCookie = rbuGetU32(&pBuf[24]);
+      p->iWriteVer = pBuf[19];
     }
+  }
+  return rc;
+}
+
+/*
+** Write data to an rbuVfs-file.
+*/
+static int rbuVfsWrite(
+  sqlite3_file *pFile, 
+  const void *zBuf, 
+  int iAmt, 
+  sqlite_int64 iOfst
+){
+  rbu_file *p = (rbu_file*)pFile;
+  sqlite3rbu *pRbu = p->pRbu;
+  int rc;
+
+  if( pRbu && pRbu->eStage==RBU_STAGE_CAPTURE ){
+    assert( p->openFlags & SQLITE_OPEN_MAIN_DB );
+    rc = rbuCaptureDbWrite(p->pRbu, iOfst);
   }else{
-    nByte = 1;
-    if( aBuf ) aBuf[0] = '\0';
+    if( pRbu ){
+      if( pRbu->eStage==RBU_STAGE_OAL 
+       && (p->openFlags & SQLITE_OPEN_WAL) 
+       && iOfst>=pRbu->iOalSz
+      ){
+        pRbu->iOalSz = iAmt + iOfst;
+      }else if( p->openFlags & SQLITE_OPEN_DELETEONCLOSE ){
+        i64 szNew = iAmt+iOfst;
+        if( szNew>p->sz ){
+          rc = rbuUpdateTempSize(p, szNew);
+          if( rc!=SQLITE_OK ) return rc;
+        }
+      }
+    }
+    rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
+    if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
+      /* These look like magic numbers. But they are stable, as they are part
+      ** of the definition of the SQLite file format, which may not change. */
+      u8 *pBuf = (u8*)zBuf;
+      p->iCookie = rbuGetU32(&pBuf[24]);
+      p->iWriteVer = pBuf[19];
+    }
   }
+  return rc;
+}
 
-  if( pnWrite ) *pnWrite += nByte;
-  return SQLITE_OK;
+/*
+** Truncate an rbuVfs-file.
+*/
+static int rbuVfsTruncate(sqlite3_file *pFile, sqlite_int64 size){
+  rbu_file *p = (rbu_file*)pFile;
+  if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){
+    int rc = rbuUpdateTempSize(p, size);
+    if( rc!=SQLITE_OK ) return rc;
+  }
+  return p->pReal->pMethods->xTruncate(p->pReal, size);
 }
 
+/*
+** Sync an rbuVfs-file.
+*/
+static int rbuVfsSync(sqlite3_file *pFile, int flags){
+  rbu_file *p = (rbu_file *)pFile;
+  if( p->pRbu && p->pRbu->eStage==RBU_STAGE_CAPTURE ){
+    if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
+      return SQLITE_INTERNAL;
+    }
+    return SQLITE_OK;
+  }
+  return p->pReal->pMethods->xSync(p->pReal, flags);
+}
 
 /*
-** This macro is used to calculate hash key values for data structures. In
-** order to use this macro, the entire data structure must be represented
-** as a series of unsigned integers. In order to calculate a hash-key value
-** for a data structure represented as three such integers, the macro may
-** then be used as follows:
-**
-**    int hash_key_value;
-**    hash_key_value = HASH_APPEND(0, <value 1>);
-**    hash_key_value = HASH_APPEND(hash_key_value, <value 2>);
-**    hash_key_value = HASH_APPEND(hash_key_value, <value 3>);
-**
-** In practice, the data structures this macro is used for are the primary
-** key values of modified rows.
+** Return the current file-size of an rbuVfs-file.
 */
-#define HASH_APPEND(hash, add) ((hash) << 3) ^ (hash) ^ (unsigned int)(add)
+static int rbuVfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
+  rbu_file *p = (rbu_file *)pFile;
+  int rc;
+  rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
+
+  /* If this is an RBU vacuum operation and this is the target database,
+  ** pretend that it has at least one page. Otherwise, SQLite will not
+  ** check for the existance of a *-wal file. rbuVfsRead() contains 
+  ** similar logic.  */
+  if( rc==SQLITE_OK && *pSize==0 
+   && p->pRbu && rbuIsVacuum(p->pRbu) 
+   && (p->openFlags & SQLITE_OPEN_MAIN_DB)
+  ){
+    *pSize = 1024;
+  }
+  return rc;
+}
 
 /*
-** Append the hash of the 64-bit integer passed as the second argument to the
-** hash-key value passed as the first. Return the new hash-key value.
+** Lock an rbuVfs-file.
 */
-static unsigned int sessionHashAppendI64(unsigned int h, i64 i){
-  h = HASH_APPEND(h, i & 0xFFFFFFFF);
-  return HASH_APPEND(h, (i>>32)&0xFFFFFFFF);
+static int rbuVfsLock(sqlite3_file *pFile, int eLock){
+  rbu_file *p = (rbu_file*)pFile;
+  sqlite3rbu *pRbu = p->pRbu;
+  int rc = SQLITE_OK;
+
+  assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
+  if( eLock==SQLITE_LOCK_EXCLUSIVE 
+   && (p->bNolock || (pRbu && pRbu->eStage!=RBU_STAGE_DONE))
+  ){
+    /* Do not allow EXCLUSIVE locks. Preventing SQLite from taking this 
+    ** prevents it from checkpointing the database from sqlite3_close(). */
+    rc = SQLITE_BUSY;
+  }else{
+    rc = p->pReal->pMethods->xLock(p->pReal, eLock);
+  }
+
+  return rc;
 }
 
 /*
-** Append the hash of the blob passed via the second and third arguments to 
-** the hash-key value passed as the first. Return the new hash-key value.
+** Unlock an rbuVfs-file.
 */
-static unsigned int sessionHashAppendBlob(unsigned int h, int n, const u8 *z){
-  int i;
-  for(i=0; i<n; i++) h = HASH_APPEND(h, z[i]);
-  return h;
+static int rbuVfsUnlock(sqlite3_file *pFile, int eLock){
+  rbu_file *p = (rbu_file *)pFile;
+  return p->pReal->pMethods->xUnlock(p->pReal, eLock);
 }
 
 /*
-** Append the hash of the data type passed as the second argument to the
-** hash-key value passed as the first. Return the new hash-key value.
+** Check if another file-handle holds a RESERVED lock on an rbuVfs-file.
 */
-static unsigned int sessionHashAppendType(unsigned int h, int eType){
-  return HASH_APPEND(h, eType);
+static int rbuVfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){
+  rbu_file *p = (rbu_file *)pFile;
+  return p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
 }
 
 /*
-** This function may only be called from within a pre-update callback.
-** It calculates a hash based on the primary key values of the old.* or 
-** new.* row currently available and, assuming no error occurs, writes it to
-** *piHash before returning. If the primary key contains one or more NULL
-** values, *pbNullPK is set to true before returning.
-**
-** If an error occurs, an SQLite error code is returned and the final values
-** of *piHash asn *pbNullPK are undefined. Otherwise, SQLITE_OK is returned
-** and the output variables are set as described above.
+** File control method. For custom operations on an rbuVfs-file.
 */
-static int sessionPreupdateHash(
-  sqlite3_session *pSession,      /* Session object that owns pTab */
-  SessionTable *pTab,             /* Session table handle */
-  int bNew,                       /* True to hash the new.* PK */
-  int *piHash,                    /* OUT: Hash value */
-  int *pbNullPK                   /* OUT: True if there are NULL values in PK */
-){
-  unsigned int h = 0;             /* Hash value to return */
-  int i;                          /* Used to iterate through columns */
+static int rbuVfsFileControl(sqlite3_file *pFile, int op, void *pArg){
+  rbu_file *p = (rbu_file *)pFile;
+  int (*xControl)(sqlite3_file*,int,void*) = p->pReal->pMethods->xFileControl;
+  int rc;
 
-  assert( *pbNullPK==0 );
-  assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) );
-  for(i=0; i<pTab->nCol; i++){
-    if( pTab->abPK[i] ){
-      int rc;
-      int eType;
-      sqlite3_value *pVal;
+  assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB)
+       || p->openFlags & (SQLITE_OPEN_TRANSIENT_DB|SQLITE_OPEN_TEMP_JOURNAL)
+  );
+  if( op==SQLITE_FCNTL_RBU ){
+    sqlite3rbu *pRbu = (sqlite3rbu*)pArg;
 
-      if( bNew ){
-        rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal);
-      }else{
-        rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal);
-      }
-      if( rc!=SQLITE_OK ) return rc;
+    /* First try to find another RBU vfs lower down in the vfs stack. If
+    ** one is found, this vfs will operate in pass-through mode. The lower
+    ** level vfs will do the special RBU handling.  */
+    rc = xControl(p->pReal, op, pArg);
 
-      eType = sqlite3_value_type(pVal);
-      h = sessionHashAppendType(h, eType);
-      if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
-        i64 iVal;
-        if( eType==SQLITE_INTEGER ){
-          iVal = sqlite3_value_int64(pVal);
-        }else{
-          double rVal = sqlite3_value_double(pVal);
-          assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
-          memcpy(&iVal, &rVal, 8);
-        }
-        h = sessionHashAppendI64(h, iVal);
-      }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
-        const u8 *z;
-        int n;
-        if( eType==SQLITE_TEXT ){
-          z = (const u8 *)sqlite3_value_text(pVal);
-        }else{
-          z = (const u8 *)sqlite3_value_blob(pVal);
-        }
-        n = sqlite3_value_bytes(pVal);
-        if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
-        h = sessionHashAppendBlob(h, n, z);
-      }else{
-        assert( eType==SQLITE_NULL );
-        assert( pTab->bStat1==0 || i!=1 );
-        *pbNullPK = 1;
+    if( rc==SQLITE_NOTFOUND ){
+      /* Now search for a zipvfs instance lower down in the VFS stack. If
+      ** one is found, this is an error.  */
+      void *dummy = 0;
+      rc = xControl(p->pReal, SQLITE_FCNTL_ZIPVFS, &dummy);
+      if( rc==SQLITE_OK ){
+        rc = SQLITE_ERROR;
+        pRbu->zErrmsg = sqlite3_mprintf("rbu/zipvfs setup error");
+      }else if( rc==SQLITE_NOTFOUND ){
+        pRbu->pTargetFd = p;
+        p->pRbu = pRbu;
+        if( p->pWalFd ) p->pWalFd->pRbu = pRbu;
+        rc = SQLITE_OK;
       }
     }
+    return rc;
+  }
+  else if( op==SQLITE_FCNTL_RBUCNT ){
+    sqlite3rbu *pRbu = (sqlite3rbu*)pArg;
+    pRbu->nRbu++;
+    pRbu->pRbuFd = p;
+    p->bNolock = 1;
+  }
+
+  rc = xControl(p->pReal, op, pArg);
+  if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){
+    rbu_vfs *pRbuVfs = p->pRbuVfs;
+    char *zIn = *(char**)pArg;
+    char *zOut = sqlite3_mprintf("rbu(%s)/%z", pRbuVfs->base.zName, zIn);
+    *(char**)pArg = zOut;
+    if( zOut==0 ) rc = SQLITE_NOMEM;
   }
 
-  *piHash = (h % pTab->nChange);
-  return SQLITE_OK;
+  return rc;
 }
 
 /*
-** The buffer that the argument points to contains a serialized SQL value.
-** Return the number of bytes of space occupied by the value (including
-** the type byte).
+** Return the sector-size in bytes for an rbuVfs-file.
 */
-static int sessionSerialLen(u8 *a){
-  int e = *a;
-  int n;
-  if( e==0 || e==0xFF ) return 1;
-  if( e==SQLITE_NULL ) return 1;
-  if( e==SQLITE_INTEGER || e==SQLITE_FLOAT ) return 9;
-  return sessionVarintGet(&a[1], &n) + 1 + n;
+static int rbuVfsSectorSize(sqlite3_file *pFile){
+  rbu_file *p = (rbu_file *)pFile;
+  return p->pReal->pMethods->xSectorSize(p->pReal);
 }
 
 /*
-** Based on the primary key values stored in change aRecord, calculate a
-** hash key. Assume the has table has nBucket buckets. The hash keys
-** calculated by this function are compatible with those calculated by
-** sessionPreupdateHash().
-**
-** The bPkOnly argument is non-zero if the record at aRecord[] is from
-** a patchset DELETE. In this case the non-PK fields are omitted entirely.
+** Return the device characteristic flags supported by an rbuVfs-file.
 */
-static unsigned int sessionChangeHash(
-  SessionTable *pTab,             /* Table handle */
-  int bPkOnly,                    /* Record consists of PK fields only */
-  u8 *aRecord,                    /* Change record */
-  int nBucket                     /* Assume this many buckets in hash table */
-){
-  unsigned int h = 0;             /* Value to return */
-  int i;                          /* Used to iterate through columns */
-  u8 *a = aRecord;                /* Used to iterate through change record */
+static int rbuVfsDeviceCharacteristics(sqlite3_file *pFile){
+  rbu_file *p = (rbu_file *)pFile;
+  return p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
+}
 
-  for(i=0; i<pTab->nCol; i++){
-    int eType = *a;
-    int isPK = pTab->abPK[i];
-    if( bPkOnly && isPK==0 ) continue;
+/*
+** Take or release a shared-memory lock.
+*/
+static int rbuVfsShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
+  rbu_file *p = (rbu_file*)pFile;
+  sqlite3rbu *pRbu = p->pRbu;
+  int rc = SQLITE_OK;
 
-    /* It is not possible for eType to be SQLITE_NULL here. The session 
-    ** module does not record changes for rows with NULL values stored in
-    ** primary key columns. */
-    assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT 
-         || eType==SQLITE_TEXT || eType==SQLITE_BLOB 
-         || eType==SQLITE_NULL || eType==0 
-    );
-    assert( !isPK || (eType!=0 && eType!=SQLITE_NULL) );
+#ifdef SQLITE_AMALGAMATION
+    assert( WAL_CKPT_LOCK==1 );
+#endif
 
-    if( isPK ){
-      a++;
-      h = sessionHashAppendType(h, eType);
-      if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
-        h = sessionHashAppendI64(h, sessionGetI64(a));
-        a += 8;
-      }else{
-        int n; 
-        a += sessionVarintGet(a, &n);
-        h = sessionHashAppendBlob(h, n, a);
-        a += n;
+  assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
+  if( pRbu && (pRbu->eStage==RBU_STAGE_OAL || pRbu->eStage==RBU_STAGE_MOVE) ){
+    /* Magic number 1 is the WAL_CKPT_LOCK lock. Preventing SQLite from
+    ** taking this lock also prevents any checkpoints from occurring. 
+    ** todo: really, it's not clear why this might occur, as 
+    ** wal_autocheckpoint ought to be turned off.  */
+    if( ofst==WAL_LOCK_CKPT && n==1 ) rc = SQLITE_BUSY;
+  }else{
+    int bCapture = 0;
+    if( n==1 && (flags & SQLITE_SHM_EXCLUSIVE)
+     && pRbu && pRbu->eStage==RBU_STAGE_CAPTURE
+     && (ofst==WAL_LOCK_WRITE || ofst==WAL_LOCK_CKPT || ofst==WAL_LOCK_READ0)
+    ){
+      bCapture = 1;
+    }
+
+    if( bCapture==0 || 0==(flags & SQLITE_SHM_UNLOCK) ){
+      rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
+      if( bCapture && rc==SQLITE_OK ){
+        pRbu->mLock |= (1 << ofst);
       }
-    }else{
-      a += sessionSerialLen(a);
     }
   }
-  return (h % nBucket);
+
+  return rc;
 }
 
 /*
-** Arguments aLeft and aRight are pointers to change records for table pTab.
-** This function returns true if the two records apply to the same row (i.e.
-** have the same values stored in the primary key columns), or false 
-** otherwise.
+** Obtain a pointer to a mapping of a single 32KiB page of the *-shm file.
 */
-static int sessionChangeEqual(
-  SessionTable *pTab,             /* Table used for PK definition */
-  int bLeftPkOnly,                /* True if aLeft[] contains PK fields only */
-  u8 *aLeft,                      /* Change record */
-  int bRightPkOnly,               /* True if aRight[] contains PK fields only */
-  u8 *aRight                      /* Change record */
+static int rbuVfsShmMap(
+  sqlite3_file *pFile, 
+  int iRegion, 
+  int szRegion, 
+  int isWrite, 
+  void volatile **pp
 ){
-  u8 *a1 = aLeft;                 /* Cursor to iterate through aLeft */
-  u8 *a2 = aRight;                /* Cursor to iterate through aRight */
-  int iCol;                       /* Used to iterate through table columns */
+  rbu_file *p = (rbu_file*)pFile;
+  int rc = SQLITE_OK;
+  int eStage = (p->pRbu ? p->pRbu->eStage : 0);
 
-  for(iCol=0; iCol<pTab->nCol; iCol++){
-    if( pTab->abPK[iCol] ){
-      int n1 = sessionSerialLen(a1);
-      int n2 = sessionSerialLen(a2);
+  /* If not in RBU_STAGE_OAL, allow this call to pass through. Or, if this
+  ** rbu is in the RBU_STAGE_OAL state, use heap memory for *-shm space 
+  ** instead of a file on disk.  */
+  assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
+  if( eStage==RBU_STAGE_OAL || eStage==RBU_STAGE_MOVE ){
+    if( iRegion<=p->nShm ){
+      int nByte = (iRegion+1) * sizeof(char*);
+      char **apNew = (char**)sqlite3_realloc64(p->apShm, nByte);
+      if( apNew==0 ){
+        rc = SQLITE_NOMEM;
+      }else{
+        memset(&apNew[p->nShm], 0, sizeof(char*) * (1 + iRegion - p->nShm));
+        p->apShm = apNew;
+        p->nShm = iRegion+1;
+      }
+    }
 
-      if( n1!=n2 || memcmp(a1, a2, n1) ){
-        return 0;
+    if( rc==SQLITE_OK && p->apShm[iRegion]==0 ){
+      char *pNew = (char*)sqlite3_malloc64(szRegion);
+      if( pNew==0 ){
+        rc = SQLITE_NOMEM;
+      }else{
+        memset(pNew, 0, szRegion);
+        p->apShm[iRegion] = pNew;
       }
-      a1 += n1;
-      a2 += n2;
+    }
+
+    if( rc==SQLITE_OK ){
+      *pp = p->apShm[iRegion];
     }else{
-      if( bLeftPkOnly==0 ) a1 += sessionSerialLen(a1);
-      if( bRightPkOnly==0 ) a2 += sessionSerialLen(a2);
+      *pp = 0;
     }
+  }else{
+    assert( p->apShm==0 );
+    rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
   }
 
-  return 1;
+  return rc;
 }
 
 /*
-** Arguments aLeft and aRight both point to buffers containing change
-** records with nCol columns. This function "merges" the two records into
-** a single records which is written to the buffer at *paOut. *paOut is
-** then set to point to one byte after the last byte written before 
-** returning.
-**
-** The merging of records is done as follows: For each column, if the 
-** aRight record contains a value for the column, copy the value from
-** their. Otherwise, if aLeft contains a value, copy it. If neither
-** record contains a value for a given column, then neither does the
-** output record.
+** Memory barrier.
 */
-static void sessionMergeRecord(
-  u8 **paOut, 
-  int nCol,
-  u8 *aLeft,
-  u8 *aRight
-){
-  u8 *a1 = aLeft;                 /* Cursor used to iterate through aLeft */
-  u8 *a2 = aRight;                /* Cursor used to iterate through aRight */
-  u8 *aOut = *paOut;              /* Output cursor */
-  int iCol;                       /* Used to iterate from 0 to nCol */
+static void rbuVfsShmBarrier(sqlite3_file *pFile){
+  rbu_file *p = (rbu_file *)pFile;
+  p->pReal->pMethods->xShmBarrier(p->pReal);
+}
 
-  for(iCol=0; iCol<nCol; iCol++){
-    int n1 = sessionSerialLen(a1);
-    int n2 = sessionSerialLen(a2);
-    if( *a2 ){
-      memcpy(aOut, a2, n2);
-      aOut += n2;
-    }else{
-      memcpy(aOut, a1, n1);
-      aOut += n1;
-    }
-    a1 += n1;
-    a2 += n2;
-  }
+/*
+** The xShmUnmap method.
+*/
+static int rbuVfsShmUnmap(sqlite3_file *pFile, int delFlag){
+  rbu_file *p = (rbu_file*)pFile;
+  int rc = SQLITE_OK;
+  int eStage = (p->pRbu ? p->pRbu->eStage : 0);
 
-  *paOut = aOut;
+  assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
+  if( eStage==RBU_STAGE_OAL || eStage==RBU_STAGE_MOVE ){
+    /* no-op */
+  }else{
+    /* Release the checkpointer and writer locks */
+    rbuUnlockShm(p);
+    rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
+  }
+  return rc;
 }
 
 /*
-** This is a helper function used by sessionMergeUpdate().
-**
-** When this function is called, both *paOne and *paTwo point to a value 
-** within a change record. Before it returns, both have been advanced so 
-** as to point to the next value in the record.
-**
-** If, when this function is called, *paTwo points to a valid value (i.e.
-** *paTwo[0] is not 0x00 - the "no value" placeholder), a copy of the *paTwo
-** pointer is returned and *pnVal is set to the number of bytes in the 
-** serialized value. Otherwise, a copy of *paOne is returned and *pnVal
-** set to the number of bytes in the value at *paOne. If *paOne points
-** to the "no value" placeholder, *pnVal is set to 1. In other words:
-**
-**   if( *paTwo is valid ) return *paTwo;
-**   return *paOne;
-**
+** Given that zWal points to a buffer containing a wal file name passed to 
+** either the xOpen() or xAccess() VFS method, return a pointer to the
+** file-handle opened by the same database connection on the corresponding
+** database file.
 */
-static u8 *sessionMergeValue(
-  u8 **paOne,                     /* IN/OUT: Left-hand buffer pointer */
-  u8 **paTwo,                     /* IN/OUT: Right-hand buffer pointer */
-  int *pnVal                      /* OUT: Bytes in returned value */
-){
-  u8 *a1 = *paOne;
-  u8 *a2 = *paTwo;
-  u8 *pRet = 0;
-  int n1;
+static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal){
+  rbu_file *pDb;
+  sqlite3_mutex_enter(pRbuVfs->mutex);
+  for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){}
+  sqlite3_mutex_leave(pRbuVfs->mutex);
+  return pDb;
+}
 
-  assert( a1 );
-  if( a2 ){
-    int n2 = sessionSerialLen(a2);
-    if( *a2 ){
-      *pnVal = n2;
-      pRet = a2;
+/* 
+** A main database named zName has just been opened. The following 
+** function returns a pointer to a buffer owned by SQLite that contains
+** the name of the *-wal file this db connection will use. SQLite
+** happens to pass a pointer to this buffer when using xAccess()
+** or xOpen() to operate on the *-wal file.  
+*/
+static const char *rbuMainToWal(const char *zName, int flags){
+  int n = (int)strlen(zName);
+  const char *z = &zName[n];
+  if( flags & SQLITE_OPEN_URI ){
+    int odd = 0;
+    while( 1 ){
+      if( z[0]==0 ){
+        odd = 1 - odd;
+        if( odd && z[1]==0 ) break;
+      }
+      z++;
     }
-    *paTwo = &a2[n2];
-  }
-
-  n1 = sessionSerialLen(a1);
-  if( pRet==0 ){
-    *pnVal = n1;
-    pRet = a1;
+    z += 2;
+  }else{
+    while( *z==0 ) z++;
   }
-  *paOne = &a1[n1];
-
-  return pRet;
+  z += (n + 8 + 1);
+  return z;
 }
 
 /*
-** This function is used by changeset_concat() to merge two UPDATE changes
-** on the same row.
+** Open an rbu file handle.
 */
-static int sessionMergeUpdate(
-  u8 **paOut,                     /* IN/OUT: Pointer to output buffer */
-  SessionTable *pTab,             /* Table change pertains to */
-  int bPatchset,                  /* True if records are patchset records */
-  u8 *aOldRecord1,                /* old.* record for first change */
-  u8 *aOldRecord2,                /* old.* record for second change */
-  u8 *aNewRecord1,                /* new.* record for first change */
-  u8 *aNewRecord2                 /* new.* record for second change */
+static int rbuVfsOpen(
+  sqlite3_vfs *pVfs,
+  const char *zName,
+  sqlite3_file *pFile,
+  int flags,
+  int *pOutFlags
 ){
-  u8 *aOld1 = aOldRecord1;
-  u8 *aOld2 = aOldRecord2;
-  u8 *aNew1 = aNewRecord1;
-  u8 *aNew2 = aNewRecord2;
-
-  u8 *aOut = *paOut;
-  int i;
-
-  if( bPatchset==0 ){
-    int bRequired = 0;
-
-    assert( aOldRecord1 && aNewRecord1 );
-
-    /* Write the old.* vector first. */
-    for(i=0; i<pTab->nCol; i++){
-      int nOld;
-      u8 *aOld;
-      int nNew;
-      u8 *aNew;
+  static sqlite3_io_methods rbuvfs_io_methods = {
+    2,                            /* iVersion */
+    rbuVfsClose,                  /* xClose */
+    rbuVfsRead,                   /* xRead */
+    rbuVfsWrite,                  /* xWrite */
+    rbuVfsTruncate,               /* xTruncate */
+    rbuVfsSync,                   /* xSync */
+    rbuVfsFileSize,               /* xFileSize */
+    rbuVfsLock,                   /* xLock */
+    rbuVfsUnlock,                 /* xUnlock */
+    rbuVfsCheckReservedLock,      /* xCheckReservedLock */
+    rbuVfsFileControl,            /* xFileControl */
+    rbuVfsSectorSize,             /* xSectorSize */
+    rbuVfsDeviceCharacteristics,  /* xDeviceCharacteristics */
+    rbuVfsShmMap,                 /* xShmMap */
+    rbuVfsShmLock,                /* xShmLock */
+    rbuVfsShmBarrier,             /* xShmBarrier */
+    rbuVfsShmUnmap,               /* xShmUnmap */
+    0, 0                          /* xFetch, xUnfetch */
+  };
+  rbu_vfs *pRbuVfs = (rbu_vfs*)pVfs;
+  sqlite3_vfs *pRealVfs = pRbuVfs->pRealVfs;
+  rbu_file *pFd = (rbu_file *)pFile;
+  int rc = SQLITE_OK;
+  const char *zOpen = zName;
+  int oflags = flags;
 
-      aOld = sessionMergeValue(&aOld1, &aOld2, &nOld);
-      aNew = sessionMergeValue(&aNew1, &aNew2, &nNew);
-      if( pTab->abPK[i] || nOld!=nNew || memcmp(aOld, aNew, nNew) ){
-        if( pTab->abPK[i]==0 ) bRequired = 1;
-        memcpy(aOut, aOld, nOld);
-        aOut += nOld;
-      }else{
-        *(aOut++) = '\0';
+  memset(pFd, 0, sizeof(rbu_file));
+  pFd->pReal = (sqlite3_file*)&pFd[1];
+  pFd->pRbuVfs = pRbuVfs;
+  pFd->openFlags = flags;
+  if( zName ){
+    if( flags & SQLITE_OPEN_MAIN_DB ){
+      /* A main database has just been opened. The following block sets
+      ** (pFd->zWal) to point to a buffer owned by SQLite that contains
+      ** the name of the *-wal file this db connection will use. SQLite
+      ** happens to pass a pointer to this buffer when using xAccess()
+      ** or xOpen() to operate on the *-wal file.  */
+      pFd->zWal = rbuMainToWal(zName, flags);
+    }
+    else if( flags & SQLITE_OPEN_WAL ){
+      rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName);
+      if( pDb ){
+        if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
+          /* This call is to open a *-wal file. Intead, open the *-oal. This
+          ** code ensures that the string passed to xOpen() is terminated by a
+          ** pair of '\0' bytes in case the VFS attempts to extract a URI 
+          ** parameter from it.  */
+          const char *zBase = zName;
+          size_t nCopy;
+          char *zCopy;
+          if( rbuIsVacuum(pDb->pRbu) ){
+            zBase = sqlite3_db_filename(pDb->pRbu->dbRbu, "main");
+            zBase = rbuMainToWal(zBase, SQLITE_OPEN_URI);
+          }
+          nCopy = strlen(zBase);
+          zCopy = sqlite3_malloc64(nCopy+2);
+          if( zCopy ){
+            memcpy(zCopy, zBase, nCopy);
+            zCopy[nCopy-3] = 'o';
+            zCopy[nCopy] = '\0';
+            zCopy[nCopy+1] = '\0';
+            zOpen = (const char*)(pFd->zDel = zCopy);
+          }else{
+            rc = SQLITE_NOMEM;
+          }
+          pFd->pRbu = pDb->pRbu;
+        }
+        pDb->pWalFd = pFd;
       }
     }
-
-    if( !bRequired ) return 0;
+  }else{
+    pFd->pRbu = pRbuVfs->pRbu;
   }
 
-  /* Write the new.* vector */
-  aOld1 = aOldRecord1;
-  aOld2 = aOldRecord2;
-  aNew1 = aNewRecord1;
-  aNew2 = aNewRecord2;
-  for(i=0; i<pTab->nCol; i++){
-    int nOld;
-    u8 *aOld;
-    int nNew;
-    u8 *aNew;
+  if( oflags & SQLITE_OPEN_MAIN_DB 
+   && sqlite3_uri_boolean(zName, "rbu_memory", 0) 
+  ){
+    assert( oflags & SQLITE_OPEN_MAIN_DB );
+    oflags =  SQLITE_OPEN_TEMP_DB | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
+              SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE;
+    zOpen = 0;
+  }
 
-    aOld = sessionMergeValue(&aOld1, &aOld2, &nOld);
-    aNew = sessionMergeValue(&aNew1, &aNew2, &nNew);
-    if( bPatchset==0 
-     && (pTab->abPK[i] || (nOld==nNew && 0==memcmp(aOld, aNew, nNew))) 
-    ){
-      *(aOut++) = '\0';
-    }else{
-      memcpy(aOut, aNew, nNew);
-      aOut += nNew;
+  if( rc==SQLITE_OK ){
+    rc = pRealVfs->xOpen(pRealVfs, zOpen, pFd->pReal, oflags, pOutFlags);
+  }
+  if( pFd->pReal->pMethods ){
+    /* The xOpen() operation has succeeded. Set the sqlite3_file.pMethods
+    ** pointer and, if the file is a main database file, link it into the
+    ** mutex protected linked list of all such files.  */
+    pFile->pMethods = &rbuvfs_io_methods;
+    if( flags & SQLITE_OPEN_MAIN_DB ){
+      sqlite3_mutex_enter(pRbuVfs->mutex);
+      pFd->pMainNext = pRbuVfs->pMain;
+      pRbuVfs->pMain = pFd;
+      sqlite3_mutex_leave(pRbuVfs->mutex);
     }
+  }else{
+    sqlite3_free(pFd->zDel);
   }
 
-  *paOut = aOut;
-  return 1;
+  return rc;
 }
 
 /*
-** This function is only called from within a pre-update-hook callback.
-** It determines if the current pre-update-hook change affects the same row
-** as the change stored in argument pChange. If so, it returns true. Otherwise
-** if the pre-update-hook does not affect the same row as pChange, it returns
-** false.
+** Delete the file located at zPath.
 */
-static int sessionPreupdateEqual(
-  sqlite3_session *pSession,      /* Session object that owns SessionTable */
-  SessionTable *pTab,             /* Table associated with change */
-  SessionChange *pChange,         /* Change to compare to */
-  int op                          /* Current pre-update operation */
-){
-  int iCol;                       /* Used to iterate through columns */
-  u8 *a = pChange->aRecord;       /* Cursor used to scan change record */
-
-  assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE );
-  for(iCol=0; iCol<pTab->nCol; iCol++){
-    if( !pTab->abPK[iCol] ){
-      a += sessionSerialLen(a);
-    }else{
-      sqlite3_value *pVal;        /* Value returned by preupdate_new/old */
-      int rc;                     /* Error code from preupdate_new/old */
-      int eType = *a++;           /* Type of value from change record */
+static int rbuVfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
+  sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
+  return pRealVfs->xDelete(pRealVfs, zPath, dirSync);
+}
 
-      /* The following calls to preupdate_new() and preupdate_old() can not
-      ** fail. This is because they cache their return values, and by the
-      ** time control flows to here they have already been called once from
-      ** within sessionPreupdateHash(). The first two asserts below verify
-      ** this (that the method has already been called). */
-      if( op==SQLITE_INSERT ){
-        /* assert( db->pPreUpdate->pNewUnpacked || db->pPreUpdate->aNew ); */
-        rc = pSession->hook.xNew(pSession->hook.pCtx, iCol, &pVal);
-      }else{
-        /* assert( db->pPreUpdate->pUnpacked ); */
-        rc = pSession->hook.xOld(pSession->hook.pCtx, iCol, &pVal);
-      }
-      assert( rc==SQLITE_OK );
-      if( sqlite3_value_type(pVal)!=eType ) return 0;
+/*
+** Test for access permissions. Return true if the requested permission
+** is available, or false otherwise.
+*/
+static int rbuVfsAccess(
+  sqlite3_vfs *pVfs, 
+  const char *zPath, 
+  int flags, 
+  int *pResOut
+){
+  rbu_vfs *pRbuVfs = (rbu_vfs*)pVfs;
+  sqlite3_vfs *pRealVfs = pRbuVfs->pRealVfs;
+  int rc;
 
-      /* A SessionChange object never has a NULL value in a PK column */
-      assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT
-           || eType==SQLITE_BLOB    || eType==SQLITE_TEXT
-      );
+  rc = pRealVfs->xAccess(pRealVfs, zPath, flags, pResOut);
 
-      if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
-        i64 iVal = sessionGetI64(a);
-        a += 8;
-        if( eType==SQLITE_INTEGER ){
-          if( sqlite3_value_int64(pVal)!=iVal ) return 0;
-        }else{
-          double rVal;
-          assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
-          memcpy(&rVal, &iVal, 8);
-          if( sqlite3_value_double(pVal)!=rVal ) return 0;
-        }
+  /* If this call is to check if a *-wal file associated with an RBU target
+  ** database connection exists, and the RBU update is in RBU_STAGE_OAL,
+  ** the following special handling is activated:
+  **
+  **   a) if the *-wal file does exist, return SQLITE_CANTOPEN. This
+  **      ensures that the RBU extension never tries to update a database
+  **      in wal mode, even if the first page of the database file has
+  **      been damaged. 
+  **
+  **   b) if the *-wal file does not exist, claim that it does anyway,
+  **      causing SQLite to call xOpen() to open it. This call will also
+  **      be intercepted (see the rbuVfsOpen() function) and the *-oal
+  **      file opened instead.
+  */
+  if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){
+    rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath);
+    if( pDb && pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
+      if( *pResOut ){
+        rc = SQLITE_CANTOPEN;
       }else{
-        int n;
-        const u8 *z;
-        a += sessionVarintGet(a, &n);
-        if( sqlite3_value_bytes(pVal)!=n ) return 0;
-        if( eType==SQLITE_TEXT ){
-          z = sqlite3_value_text(pVal);
-        }else{
-          z = sqlite3_value_blob(pVal);
-        }
-        if( n>0 && memcmp(a, z, n) ) return 0;
-        a += n;
+        sqlite3_int64 sz = 0;
+        rc = rbuVfsFileSize(&pDb->base, &sz);
+        *pResOut = (sz>0);
       }
     }
   }
 
-  return 1;
+  return rc;
 }
 
 /*
-** If required, grow the hash table used to store changes on table pTab 
-** (part of the session pSession). If a fatal OOM error occurs, set the
-** session object to failed and return SQLITE_ERROR. Otherwise, return
-** SQLITE_OK.
-**
-** It is possible that a non-fatal OOM error occurs in this function. In
-** that case the hash-table does not grow, but SQLITE_OK is returned anyway.
-** Growing the hash table in this case is a performance optimization only,
-** it is not required for correct operation.
+** Populate buffer zOut with the full canonical pathname corresponding
+** to the pathname in zPath. zOut is guaranteed to point to a buffer
+** of at least (DEVSYM_MAX_PATHNAME+1) bytes.
 */
-static int sessionGrowHash(int bPatchset, SessionTable *pTab){
-  if( pTab->nChange==0 || pTab->nEntry>=(pTab->nChange/2) ){
-    int i;
-    SessionChange **apNew;
-    int nNew = (pTab->nChange ? pTab->nChange : 128) * 2;
-
-    apNew = (SessionChange **)sqlite3_malloc(sizeof(SessionChange *) * nNew);
-    if( apNew==0 ){
-      if( pTab->nChange==0 ){
-        return SQLITE_ERROR;
-      }
-      return SQLITE_OK;
-    }
-    memset(apNew, 0, sizeof(SessionChange *) * nNew);
-
-    for(i=0; i<pTab->nChange; i++){
-      SessionChange *p;
-      SessionChange *pNext;
-      for(p=pTab->apChange[i]; p; p=pNext){
-        int bPkOnly = (p->op==SQLITE_DELETE && bPatchset);
-        int iHash = sessionChangeHash(pTab, bPkOnly, p->aRecord, nNew);
-        pNext = p->pNext;
-        p->pNext = apNew[iHash];
-        apNew[iHash] = p;
-      }
-    }
+static int rbuVfsFullPathname(
+  sqlite3_vfs *pVfs, 
+  const char *zPath, 
+  int nOut, 
+  char *zOut
+){
+  sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
+  return pRealVfs->xFullPathname(pRealVfs, zPath, nOut, zOut);
+}
 
-    sqlite3_free(pTab->apChange);
-    pTab->nChange = nNew;
-    pTab->apChange = apNew;
-  }
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+/*
+** Open the dynamic library located at zPath and return a handle.
+*/
+static void *rbuVfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
+  sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
+  return pRealVfs->xDlOpen(pRealVfs, zPath);
+}
 
-  return SQLITE_OK;
+/*
+** Populate the buffer zErrMsg (size nByte bytes) with a human readable
+** utf-8 string describing the most recent error encountered associated 
+** with dynamic libraries.
+*/
+static void rbuVfsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
+  sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
+  pRealVfs->xDlError(pRealVfs, nByte, zErrMsg);
 }
 
 /*
-** This function queries the database for the names of the columns of table
-** zThis, in schema zDb.
-**
-** Otherwise, if they are not NULL, variable *pnCol is set to the number
-** of columns in the database table and variable *pzTab is set to point to a
-** nul-terminated copy of the table name. *pazCol (if not NULL) is set to
-** point to an array of pointers to column names. And *pabPK (again, if not
-** NULL) is set to point to an array of booleans - true if the corresponding
-** column is part of the primary key.
-**
-** For example, if the table is declared as:
-**
-**     CREATE TABLE tbl1(w, x, y, z, PRIMARY KEY(w, z));
-**
-** Then the four output variables are populated as follows:
-**
-**     *pnCol  = 4
-**     *pzTab  = "tbl1"
-**     *pazCol = {"w", "x", "y", "z"}
-**     *pabPK  = {1, 0, 0, 1}
-**
-** All returned buffers are part of the same single allocation, which must
-** be freed using sqlite3_free() by the caller
+** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
 */
-static int sessionTableInfo(
-  sqlite3 *db,                    /* Database connection */
-  const char *zDb,                /* Name of attached database (e.g. "main") */
-  const char *zThis,              /* Table name */
-  int *pnCol,                     /* OUT: number of columns */
-  const char **pzTab,             /* OUT: Copy of zThis */
-  const char ***pazCol,           /* OUT: Array of column names for table */
-  u8 **pabPK                      /* OUT: Array of booleans - true for PK col */
-){
-  char *zPragma;
-  sqlite3_stmt *pStmt;
-  int rc;
-  int nByte;
-  int nDbCol = 0;
-  int nThis;
-  int i;
-  u8 *pAlloc = 0;
-  char **azCol = 0;
-  u8 *abPK = 0;
+static void (*rbuVfsDlSym(
+  sqlite3_vfs *pVfs, 
+  void *pArg, 
+  const char *zSym
+))(void){
+  sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
+  return pRealVfs->xDlSym(pRealVfs, pArg, zSym);
+}
 
-  assert( pazCol && pabPK );
+/*
+** Close the dynamic library handle pHandle.
+*/
+static void rbuVfsDlClose(sqlite3_vfs *pVfs, void *pHandle){
+  sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
+  pRealVfs->xDlClose(pRealVfs, pHandle);
+}
+#endif /* SQLITE_OMIT_LOAD_EXTENSION */
 
-  nThis = sqlite3Strlen30(zThis);
-  if( nThis==12 && 0==sqlite3_stricmp("sqlite_stat1", zThis) ){
-    rc = sqlite3_table_column_metadata(db, zDb, zThis, 0, 0, 0, 0, 0, 0);
-    if( rc==SQLITE_OK ){
-      /* For sqlite_stat1, pretend that (tbl,idx) is the PRIMARY KEY. */
-      zPragma = sqlite3_mprintf(
-          "SELECT 0, 'tbl',  '', 0, '', 1     UNION ALL "
-          "SELECT 1, 'idx',  '', 0, '', 2     UNION ALL "
-          "SELECT 2, 'stat', '', 0, '', 0"
-      );
-    }else if( rc==SQLITE_ERROR ){
-      zPragma = sqlite3_mprintf("");
-    }else{
-      return rc;
-    }
-  }else{
-    zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
-  }
-  if( !zPragma ) return SQLITE_NOMEM;
+/*
+** Populate the buffer pointed to by zBufOut with nByte bytes of 
+** random data.
+*/
+static int rbuVfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
+  sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
+  return pRealVfs->xRandomness(pRealVfs, nByte, zBufOut);
+}
 
-  rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0);
-  sqlite3_free(zPragma);
-  if( rc!=SQLITE_OK ) return rc;
+/*
+** Sleep for nMicro microseconds. Return the number of microseconds 
+** actually slept.
+*/
+static int rbuVfsSleep(sqlite3_vfs *pVfs, int nMicro){
+  sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
+  return pRealVfs->xSleep(pRealVfs, nMicro);
+}
 
-  nByte = nThis + 1;
-  while( SQLITE_ROW==sqlite3_step(pStmt) ){
-    nByte += sqlite3_column_bytes(pStmt, 1);
-    nDbCol++;
-  }
-  rc = sqlite3_reset(pStmt);
+/*
+** Return the current time as a Julian Day number in *pTimeOut.
+*/
+static int rbuVfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
+  sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
+  return pRealVfs->xCurrentTime(pRealVfs, pTimeOut);
+}
 
-  if( rc==SQLITE_OK ){
-    nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
-    pAlloc = sqlite3_malloc(nByte);
-    if( pAlloc==0 ){
-      rc = SQLITE_NOMEM;
-    }
-  }
-  if( rc==SQLITE_OK ){
-    azCol = (char **)pAlloc;
-    pAlloc = (u8 *)&azCol[nDbCol];
-    abPK = (u8 *)pAlloc;
-    pAlloc = &abPK[nDbCol];
-    if( pzTab ){
-      memcpy(pAlloc, zThis, nThis+1);
-      *pzTab = (char *)pAlloc;
-      pAlloc += nThis+1;
-    }
-  
-    i = 0;
-    while( SQLITE_ROW==sqlite3_step(pStmt) ){
-      int nName = sqlite3_column_bytes(pStmt, 1);
-      const unsigned char *zName = sqlite3_column_text(pStmt, 1);
-      if( zName==0 ) break;
-      memcpy(pAlloc, zName, nName+1);
-      azCol[i] = (char *)pAlloc;
-      pAlloc += nName+1;
-      abPK[i] = sqlite3_column_int(pStmt, 5);
-      i++;
-    }
-    rc = sqlite3_reset(pStmt);
-  
-  }
+/*
+** No-op.
+*/
+static int rbuVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){
+  return 0;
+}
 
-  /* If successful, populate the output variables. Otherwise, zero them and
-  ** free any allocation made. An error code will be returned in this case.
-  */
-  if( rc==SQLITE_OK ){
-    *pazCol = (const char **)azCol;
-    *pabPK = abPK;
-    *pnCol = nDbCol;
-  }else{
-    *pazCol = 0;
-    *pabPK = 0;
-    *pnCol = 0;
-    if( pzTab ) *pzTab = 0;
-    sqlite3_free(azCol);
+/*
+** Deregister and destroy an RBU vfs created by an earlier call to
+** sqlite3rbu_create_vfs().
+*/
+SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName){
+  sqlite3_vfs *pVfs = sqlite3_vfs_find(zName);
+  if( pVfs && pVfs->xOpen==rbuVfsOpen ){
+    sqlite3_mutex_free(((rbu_vfs*)pVfs)->mutex);
+    sqlite3_vfs_unregister(pVfs);
+    sqlite3_free(pVfs);
   }
-  sqlite3_finalize(pStmt);
-  return rc;
 }
 
 /*
-** This function is only called from within a pre-update handler for a
-** write to table pTab, part of session pSession. If this is the first
-** write to this table, initalize the SessionTable.nCol, azCol[] and
-** abPK[] arrays accordingly.
-**
-** If an error occurs, an error code is stored in sqlite3_session.rc and
-** non-zero returned. Or, if no error occurs but the table has no primary
-** key, sqlite3_session.rc is left set to SQLITE_OK and non-zero returned to
-** indicate that updates on this table should be ignored. SessionTable.abPK 
-** is set to NULL in this case.
+** Create an RBU VFS named zName that accesses the underlying file-system
+** via existing VFS zParent. The new object is registered as a non-default
+** VFS with SQLite before returning.
 */
-static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
-  if( pTab->nCol==0 ){
-    u8 *abPK;
-    assert( pTab->azCol==0 || pTab->abPK==0 );
-    pSession->rc = sessionTableInfo(pSession->db, pSession->zDb, 
-        pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK
-    );
-    if( pSession->rc==SQLITE_OK ){
-      int i;
-      for(i=0; i<pTab->nCol; i++){
-        if( abPK[i] ){
-          pTab->abPK = abPK;
-          break;
-        }
-      }
-      if( 0==sqlite3_stricmp("sqlite_stat1", pTab->zName) ){
-        pTab->bStat1 = 1;
+SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent){
+
+  /* Template for VFS */
+  static sqlite3_vfs vfs_template = {
+    1,                            /* iVersion */
+    0,                            /* szOsFile */
+    0,                            /* mxPathname */
+    0,                            /* pNext */
+    0,                            /* zName */
+    0,                            /* pAppData */
+    rbuVfsOpen,                   /* xOpen */
+    rbuVfsDelete,                 /* xDelete */
+    rbuVfsAccess,                 /* xAccess */
+    rbuVfsFullPathname,           /* xFullPathname */
+
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+    rbuVfsDlOpen,                 /* xDlOpen */
+    rbuVfsDlError,                /* xDlError */
+    rbuVfsDlSym,                  /* xDlSym */
+    rbuVfsDlClose,                /* xDlClose */
+#else
+    0, 0, 0, 0,
+#endif
+
+    rbuVfsRandomness,             /* xRandomness */
+    rbuVfsSleep,                  /* xSleep */
+    rbuVfsCurrentTime,            /* xCurrentTime */
+    rbuVfsGetLastError,           /* xGetLastError */
+    0,                            /* xCurrentTimeInt64 (version 2) */
+    0, 0, 0                       /* Unimplemented version 3 methods */
+  };
+
+  rbu_vfs *pNew = 0;              /* Newly allocated VFS */
+  int rc = SQLITE_OK;
+  size_t nName;
+  size_t nByte;
+
+  nName = strlen(zName);
+  nByte = sizeof(rbu_vfs) + nName + 1;
+  pNew = (rbu_vfs*)sqlite3_malloc64(nByte);
+  if( pNew==0 ){
+    rc = SQLITE_NOMEM;
+  }else{
+    sqlite3_vfs *pParent;           /* Parent VFS */
+    memset(pNew, 0, nByte);
+    pParent = sqlite3_vfs_find(zParent);
+    if( pParent==0 ){
+      rc = SQLITE_NOTFOUND;
+    }else{
+      char *zSpace;
+      memcpy(&pNew->base, &vfs_template, sizeof(sqlite3_vfs));
+      pNew->base.mxPathname = pParent->mxPathname;
+      pNew->base.szOsFile = sizeof(rbu_file) + pParent->szOsFile;
+      pNew->pRealVfs = pParent;
+      pNew->base.zName = (const char*)(zSpace = (char*)&pNew[1]);
+      memcpy(zSpace, zName, nName);
+
+      /* Allocate the mutex and register the new VFS (not as the default) */
+      pNew->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE);
+      if( pNew->mutex==0 ){
+        rc = SQLITE_NOMEM;
+      }else{
+        rc = sqlite3_vfs_register(&pNew->base, 0);
       }
     }
+
+    if( rc!=SQLITE_OK ){
+      sqlite3_mutex_free(pNew->mutex);
+      sqlite3_free(pNew);
+    }
   }
-  return (pSession->rc || pTab->abPK==0);
+
+  return rc;
 }
 
 /*
-** Versions of the four methods in object SessionHook for use with the
-** sqlite_stat1 table. The purpose of this is to substitute a zero-length
-** blob each time a NULL value is read from the "idx" column of the
-** sqlite_stat1 table.
+** Configure the aggregate temp file size limit for this RBU handle.
 */
-typedef struct SessionStat1Ctx SessionStat1Ctx;
-struct SessionStat1Ctx {
-  SessionHook hook;
-  sqlite3_session *pSession;
-};
-static int sessionStat1Old(void *pCtx, int iCol, sqlite3_value **ppVal){
-  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
-  sqlite3_value *pVal = 0;
-  int rc = p->hook.xOld(p->hook.pCtx, iCol, &pVal);
-  if( rc==SQLITE_OK && iCol==1 && sqlite3_value_type(pVal)==SQLITE_NULL ){
-    pVal = p->pSession->pZeroBlob;
-  }
-  *ppVal = pVal;
-  return rc;
-}
-static int sessionStat1New(void *pCtx, int iCol, sqlite3_value **ppVal){
-  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
-  sqlite3_value *pVal = 0;
-  int rc = p->hook.xNew(p->hook.pCtx, iCol, &pVal);
-  if( rc==SQLITE_OK && iCol==1 && sqlite3_value_type(pVal)==SQLITE_NULL ){
-    pVal = p->pSession->pZeroBlob;
+SQLITE_API sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu *pRbu, sqlite3_int64 n){
+  if( n>=0 ){
+    pRbu->szTempLimit = n;
   }
-  *ppVal = pVal;
-  return rc;
-}
-static int sessionStat1Count(void *pCtx){
-  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
-  return p->hook.xCount(p->hook.pCtx);
+  return pRbu->szTempLimit;
 }
-static int sessionStat1Depth(void *pCtx){
-  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
-  return p->hook.xDepth(p->hook.pCtx);
+
+SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu *pRbu){
+  return pRbu->szTemp;
 }
 
 
+/**************************************************************************/
+
+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU) */
+
+/************** End of sqlite3rbu.c ******************************************/
+/************** Begin file dbstat.c ******************************************/
 /*
-** This function is only called from with a pre-update-hook reporting a 
-** change on table pTab (attached to session pSession). The type of change
-** (UPDATE, INSERT, DELETE) is specified by the first argument.
+** 2010 July 12
 **
-** Unless one is already present or an error occurs, an entry is added
-** to the changed-rows hash table associated with table pTab.
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file contains an implementation of the "dbstat" virtual table.
+**
+** The dbstat virtual table is used to extract low-level formatting
+** information from an SQLite database in order to implement the
+** "sqlite3_analyzer" utility.  See the ../tool/spaceanal.tcl script
+** for an example implementation.
+**
+** Additional information is available on the "dbstat.html" page of the
+** official SQLite documentation.
 */
-static void sessionPreupdateOneChange(
-  int op,                         /* One of SQLITE_UPDATE, INSERT, DELETE */
-  sqlite3_session *pSession,      /* Session object pTab is attached to */
-  SessionTable *pTab              /* Table that change applies to */
-){
-  int iHash; 
-  int bNull = 0; 
-  int rc = SQLITE_OK;
-  SessionStat1Ctx stat1 = {0};
 
-  if( pSession->rc ) return;
+/* #include "sqliteInt.h"   ** Requires access to internal data structures ** */
+#if (defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)) \
+    && !defined(SQLITE_OMIT_VIRTUALTABLE)
+
+/*
+** Page paths:
+** 
+**   The value of the 'path' column describes the path taken from the 
+**   root-node of the b-tree structure to each page. The value of the 
+**   root-node path is '/'.
+**
+**   The value of the path for the left-most child page of the root of
+**   a b-tree is '/000/'. (Btrees store content ordered from left to right
+**   so the pages to the left have smaller keys than the pages to the right.)
+**   The next to left-most child of the root page is
+**   '/001', and so on, each sibling page identified by a 3-digit hex 
+**   value. The children of the 451st left-most sibling have paths such
+**   as '/1c2/000/, '/1c2/001/' etc.
+**
+**   Overflow pages are specified by appending a '+' character and a 
+**   six-digit hexadecimal value to the path to the cell they are linked
+**   from. For example, the three overflow pages in a chain linked from 
+**   the left-most cell of the 450th child of the root page are identified
+**   by the paths:
+**
+**      '/1c2/000+000000'         // First page in overflow chain
+**      '/1c2/000+000001'         // Second page in overflow chain
+**      '/1c2/000+000002'         // Third page in overflow chain
+**
+**   If the paths are sorted using the BINARY collation sequence, then
+**   the overflow pages associated with a cell will appear earlier in the
+**   sort-order than its child page:
+**
+**      '/1c2/000/'               // Left-most child of 451st child of root
+*/
+#define VTAB_SCHEMA                                                         \
+  "CREATE TABLE xx( "                                                       \
+  "  name       TEXT,             /* Name of table or index */"             \
+  "  path       TEXT,             /* Path to page from root */"             \
+  "  pageno     INTEGER,          /* Page number */"                        \
+  "  pagetype   TEXT,             /* 'internal', 'leaf' or 'overflow' */"   \
+  "  ncell      INTEGER,          /* Cells on page (0 for overflow) */"     \
+  "  payload    INTEGER,          /* Bytes of payload on this page */"      \
+  "  unused     INTEGER,          /* Bytes of unused space on this page */" \
+  "  mx_payload INTEGER,          /* Largest payload size of all cells */"  \
+  "  pgoffset   INTEGER,          /* Offset of page in file */"             \
+  "  pgsize     INTEGER,          /* Size of the page */"                   \
+  "  schema     TEXT HIDDEN       /* Database schema being analyzed */"     \
+  ");"
 
-  /* Load table details if required */
-  if( sessionInitTable(pSession, pTab) ) return;
 
-  /* Check the number of columns in this xPreUpdate call matches the 
-  ** number of columns in the table.  */
-  if( pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) ){
-    pSession->rc = SQLITE_SCHEMA;
-    return;
-  }
+typedef struct StatTable StatTable;
+typedef struct StatCursor StatCursor;
+typedef struct StatPage StatPage;
+typedef struct StatCell StatCell;
 
-  /* Grow the hash table if required */
-  if( sessionGrowHash(0, pTab) ){
-    pSession->rc = SQLITE_NOMEM;
-    return;
-  }
+struct StatCell {
+  int nLocal;                     /* Bytes of local payload */
+  u32 iChildPg;                   /* Child node (or 0 if this is a leaf) */
+  int nOvfl;                      /* Entries in aOvfl[] */
+  u32 *aOvfl;                     /* Array of overflow page numbers */
+  int nLastOvfl;                  /* Bytes of payload on final overflow page */
+  int iOvfl;                      /* Iterates through aOvfl[] */
+};
 
-  if( pTab->bStat1 ){
-    stat1.hook = pSession->hook;
-    stat1.pSession = pSession;
-    pSession->hook.pCtx = (void*)&stat1;
-    pSession->hook.xNew = sessionStat1New;
-    pSession->hook.xOld = sessionStat1Old;
-    pSession->hook.xCount = sessionStat1Count;
-    pSession->hook.xDepth = sessionStat1Depth;
-    if( pSession->pZeroBlob==0 ){
-      sqlite3_value *p = sqlite3ValueNew(0);
-      if( p==0 ){
-        rc = SQLITE_NOMEM;
-        goto error_out;
-      }
-      sqlite3ValueSetStr(p, 0, "", 0, SQLITE_STATIC);
-      pSession->pZeroBlob = p;
-    }
-  }
+struct StatPage {
+  u32 iPgno;
+  DbPage *pPg;
+  int iCell;
 
-  /* Calculate the hash-key for this change. If the primary key of the row
-  ** includes a NULL value, exit early. Such changes are ignored by the
-  ** session module. */
-  rc = sessionPreupdateHash(pSession, pTab, op==SQLITE_INSERT, &iHash, &bNull);
-  if( rc!=SQLITE_OK ) goto error_out;
+  char *zPath;                    /* Path to this page */
 
-  if( bNull==0 ){
-    /* Search the hash table for an existing record for this row. */
-    SessionChange *pC;
-    for(pC=pTab->apChange[iHash]; pC; pC=pC->pNext){
-      if( sessionPreupdateEqual(pSession, pTab, pC, op) ) break;
-    }
+  /* Variables populated by statDecodePage(): */
+  u8 flags;                       /* Copy of flags byte */
+  int nCell;                      /* Number of cells on page */
+  int nUnused;                    /* Number of unused bytes on page */
+  StatCell *aCell;                /* Array of parsed cells */
+  u32 iRightChildPg;              /* Right-child page number (or 0) */
+  int nMxPayload;                 /* Largest payload of any cell on this page */
+};
 
-    if( pC==0 ){
-      /* Create a new change object containing all the old values (if
-      ** this is an SQLITE_UPDATE or SQLITE_DELETE), or just the PK
-      ** values (if this is an INSERT). */
-      SessionChange *pChange; /* New change object */
-      int nByte;              /* Number of bytes to allocate */
-      int i;                  /* Used to iterate through columns */
-  
-      assert( rc==SQLITE_OK );
-      pTab->nEntry++;
-  
-      /* Figure out how large an allocation is required */
-      nByte = sizeof(SessionChange);
-      for(i=0; i<pTab->nCol; i++){
-        sqlite3_value *p = 0;
-        if( op!=SQLITE_INSERT ){
-          TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p);
-          assert( trc==SQLITE_OK );
-        }else if( pTab->abPK[i] ){
-          TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx, i, &p);
-          assert( trc==SQLITE_OK );
-        }
+struct StatCursor {
+  sqlite3_vtab_cursor base;
+  sqlite3_stmt *pStmt;            /* Iterates through set of root pages */
+  int isEof;                      /* After pStmt has returned SQLITE_DONE */
+  int iDb;                        /* Schema used for this query */
 
-        /* This may fail if SQLite value p contains a utf-16 string that must
-        ** be converted to utf-8 and an OOM error occurs while doing so. */
-        rc = sessionSerializeValue(0, p, &nByte);
-        if( rc!=SQLITE_OK ) goto error_out;
-      }
-  
-      /* Allocate the change object */
-      pChange = (SessionChange *)sqlite3_malloc(nByte);
-      if( !pChange ){
-        rc = SQLITE_NOMEM;
-        goto error_out;
-      }else{
-        memset(pChange, 0, sizeof(SessionChange));
-        pChange->aRecord = (u8 *)&pChange[1];
-      }
-  
-      /* Populate the change object. None of the preupdate_old(),
-      ** preupdate_new() or SerializeValue() calls below may fail as all
-      ** required values and encodings have already been cached in memory.
-      ** It is not possible for an OOM to occur in this block. */
-      nByte = 0;
-      for(i=0; i<pTab->nCol; i++){
-        sqlite3_value *p = 0;
-        if( op!=SQLITE_INSERT ){
-          pSession->hook.xOld(pSession->hook.pCtx, i, &p);
-        }else if( pTab->abPK[i] ){
-          pSession->hook.xNew(pSession->hook.pCtx, i, &p);
-        }
-        sessionSerializeValue(&pChange->aRecord[nByte], p, &nByte);
-      }
+  StatPage aPage[32];
+  int iPage;                      /* Current entry in aPage[] */
 
-      /* Add the change to the hash-table */
-      if( pSession->bIndirect || pSession->hook.xDepth(pSession->hook.pCtx) ){
-        pChange->bIndirect = 1;
-      }
-      pChange->nRecord = nByte;
-      pChange->op = op;
-      pChange->pNext = pTab->apChange[iHash];
-      pTab->apChange[iHash] = pChange;
+  /* Values to return. */
+  char *zName;                    /* Value of 'name' column */
+  char *zPath;                    /* Value of 'path' column */
+  u32 iPageno;                    /* Value of 'pageno' column */
+  char *zPagetype;                /* Value of 'pagetype' column */
+  int nCell;                      /* Value of 'ncell' column */
+  int nPayload;                   /* Value of 'payload' column */
+  int nUnused;                    /* Value of 'unused' column */
+  int nMxPayload;                 /* Value of 'mx_payload' column */
+  i64 iOffset;                    /* Value of 'pgOffset' column */
+  int szPage;                     /* Value of 'pgSize' column */
+};
 
-    }else if( pC->bIndirect ){
-      /* If the existing change is considered "indirect", but this current
-      ** change is "direct", mark the change object as direct. */
-      if( pSession->hook.xDepth(pSession->hook.pCtx)==0 
-       && pSession->bIndirect==0 
-      ){
-        pC->bIndirect = 0;
-      }
-    }
-  }
+struct StatTable {
+  sqlite3_vtab base;
+  sqlite3 *db;
+  int iDb;                        /* Index of database to analyze */
+};
 
-  /* If an error has occurred, mark the session object as failed. */
- error_out:
-  if( pTab->bStat1 ){
-    pSession->hook = stat1.hook;
-  }
-  if( rc!=SQLITE_OK ){
-    pSession->rc = rc;
-  }
-}
+#ifndef get2byte
+# define get2byte(x)   ((x)[0]<<8 | (x)[1])
+#endif
 
-static int sessionFindTable(
-  sqlite3_session *pSession, 
-  const char *zName,
-  SessionTable **ppTab
+/*
+** Connect to or create a statvfs virtual table.
+*/
+static int statConnect(
+  sqlite3 *db,
+  void *pAux,
+  int argc, const char *const*argv,
+  sqlite3_vtab **ppVtab,
+  char **pzErr
 ){
+  StatTable *pTab = 0;
   int rc = SQLITE_OK;
-  int nName = sqlite3Strlen30(zName);
-  SessionTable *pRet;
+  int iDb;
 
-  /* Search for an existing table */
-  for(pRet=pSession->pTable; pRet; pRet=pRet->pNext){
-    if( 0==sqlite3_strnicmp(pRet->zName, zName, nName+1) ) break;
+  if( argc>=4 ){
+    Token nm;
+    sqlite3TokenInit(&nm, (char*)argv[3]);
+    iDb = sqlite3FindDb(db, &nm);
+    if( iDb<0 ){
+      *pzErr = sqlite3_mprintf("no such database: %s", argv[3]);
+      return SQLITE_ERROR;
+    }
+  }else{
+    iDb = 0;
+  }
+  rc = sqlite3_declare_vtab(db, VTAB_SCHEMA);
+  if( rc==SQLITE_OK ){
+    pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable));
+    if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
   }
 
-  if( pRet==0 && pSession->bAutoAttach ){
-    /* If there is a table-filter configured, invoke it. If it returns 0,
-    ** do not automatically add the new table. */
-    if( pSession->xTableFilter==0
-     || pSession->xTableFilter(pSession->pFilterCtx, zName) 
-    ){
-      rc = sqlite3session_attach(pSession, zName);
-      if( rc==SQLITE_OK ){
-        for(pRet=pSession->pTable; pRet->pNext; pRet=pRet->pNext);
-        assert( 0==sqlite3_strnicmp(pRet->zName, zName, nName+1) );
-      }
-    }
+  assert( rc==SQLITE_OK || pTab==0 );
+  if( rc==SQLITE_OK ){
+    memset(pTab, 0, sizeof(StatTable));
+    pTab->db = db;
+    pTab->iDb = iDb;
   }
 
-  assert( rc==SQLITE_OK || pRet==0 );
-  *ppTab = pRet;
+  *ppVtab = (sqlite3_vtab*)pTab;
   return rc;
 }
 
 /*
-** The 'pre-update' hook registered by this module with SQLite databases.
+** Disconnect from or destroy a statvfs virtual table.
 */
-static 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) */
-){
-  sqlite3_session *pSession;
-  int nDb = sqlite3Strlen30(zDb);
+static int statDisconnect(sqlite3_vtab *pVtab){
+  sqlite3_free(pVtab);
+  return SQLITE_OK;
+}
 
-  assert( sqlite3_mutex_held(db->mutex) );
+/*
+** There is no "best-index". This virtual table always does a linear
+** scan.  However, a schema=? constraint should cause this table to
+** operate on a different database schema, so check for it.
+**
+** idxNum is normally 0, but will be 1 if a schema=? constraint exists.
+*/
+static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
+  int i;
 
-  for(pSession=(sqlite3_session *)pCtx; pSession; pSession=pSession->pNext){
-    SessionTable *pTab;
+  pIdxInfo->estimatedCost = 1.0e6;  /* Initial cost estimate */
 
-    /* If this session is attached to a different database ("main", "temp" 
-    ** etc.), or if it is not currently enabled, there is nothing to do. Skip 
-    ** to the next session object attached to this database. */
-    if( pSession->bEnable==0 ) continue;
-    if( pSession->rc ) continue;
-    if( sqlite3_strnicmp(zDb, pSession->zDb, nDb+1) ) continue;
+  /* Look for a valid schema=? constraint.  If found, change the idxNum to
+  ** 1 and request the value of that constraint be sent to xFilter.  And
+  ** lower the cost estimate to encourage the constrained version to be
+  ** used.
+  */
+  for(i=0; i<pIdxInfo->nConstraint; i++){
+    if( pIdxInfo->aConstraint[i].usable==0 ) continue;
+    if( pIdxInfo->aConstraint[i].op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
+    if( pIdxInfo->aConstraint[i].iColumn!=10 ) continue;
+    pIdxInfo->idxNum = 1;
+    pIdxInfo->estimatedCost = 1.0;
+    pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+    pIdxInfo->aConstraintUsage[i].omit = 1;
+    break;
+  }
 
-    pSession->rc = sessionFindTable(pSession, zName, &pTab);
-    if( pTab ){
-      assert( pSession->rc==SQLITE_OK );
-      sessionPreupdateOneChange(op, pSession, pTab);
-      if( op==SQLITE_UPDATE ){
-        sessionPreupdateOneChange(SQLITE_INSERT, pSession, pTab);
-      }
-    }
+
+  /* Records are always returned in ascending order of (name, path). 
+  ** If this will satisfy the client, set the orderByConsumed flag so that 
+  ** SQLite does not do an external sort.
+  */
+  if( ( pIdxInfo->nOrderBy==1
+     && pIdxInfo->aOrderBy[0].iColumn==0
+     && pIdxInfo->aOrderBy[0].desc==0
+     ) ||
+      ( pIdxInfo->nOrderBy==2
+     && pIdxInfo->aOrderBy[0].iColumn==0
+     && pIdxInfo->aOrderBy[0].desc==0
+     && pIdxInfo->aOrderBy[1].iColumn==1
+     && pIdxInfo->aOrderBy[1].desc==0
+     )
+  ){
+    pIdxInfo->orderByConsumed = 1;
   }
-}
 
-/*
-** The pre-update hook implementations.
-*/
-static int sessionPreupdateOld(void *pCtx, int iVal, sqlite3_value **ppVal){
-  return sqlite3_preupdate_old((sqlite3*)pCtx, iVal, ppVal);
-}
-static int sessionPreupdateNew(void *pCtx, int iVal, sqlite3_value **ppVal){
-  return sqlite3_preupdate_new((sqlite3*)pCtx, iVal, ppVal);
-}
-static int sessionPreupdateCount(void *pCtx){
-  return sqlite3_preupdate_count((sqlite3*)pCtx);
-}
-static int sessionPreupdateDepth(void *pCtx){
-  return sqlite3_preupdate_depth((sqlite3*)pCtx);
+  return SQLITE_OK;
 }
 
 /*
-** Install the pre-update hooks on the session object passed as the only
-** argument.
+** Open a new statvfs cursor.
 */
-static void sessionPreupdateHooks(
-  sqlite3_session *pSession
-){
-  pSession->hook.pCtx = (void*)pSession->db;
-  pSession->hook.xOld = sessionPreupdateOld;
-  pSession->hook.xNew = sessionPreupdateNew;
-  pSession->hook.xCount = sessionPreupdateCount;
-  pSession->hook.xDepth = sessionPreupdateDepth;
-}
+static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
+  StatTable *pTab = (StatTable *)pVTab;
+  StatCursor *pCsr;
 
-typedef struct SessionDiffCtx SessionDiffCtx;
-struct SessionDiffCtx {
-  sqlite3_stmt *pStmt;
-  int nOldOff;
-};
+  pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor));
+  if( pCsr==0 ){
+    return SQLITE_NOMEM_BKPT;
+  }else{
+    memset(pCsr, 0, sizeof(StatCursor));
+    pCsr->base.pVtab = pVTab;
+    pCsr->iDb = pTab->iDb;
+  }
 
-/*
-** The diff hook implementations.
-*/
-static int sessionDiffOld(void *pCtx, int iVal, sqlite3_value **ppVal){
-  SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
-  *ppVal = sqlite3_column_value(p->pStmt, iVal+p->nOldOff);
+  *ppCursor = (sqlite3_vtab_cursor *)pCsr;
   return SQLITE_OK;
 }
-static int sessionDiffNew(void *pCtx, int iVal, sqlite3_value **ppVal){
-  SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
-  *ppVal = sqlite3_column_value(p->pStmt, iVal);
-   return SQLITE_OK;
-}
-static int sessionDiffCount(void *pCtx){
-  SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
-  return p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt);
+
+static void statClearPage(StatPage *p){
+  int i;
+  if( p->aCell ){
+    for(i=0; i<p->nCell; i++){
+      sqlite3_free(p->aCell[i].aOvfl);
+    }
+    sqlite3_free(p->aCell);
+  }
+  sqlite3PagerUnref(p->pPg);
+  sqlite3_free(p->zPath);
+  memset(p, 0, sizeof(StatPage));
 }
-static int sessionDiffDepth(void *pCtx){
-  return 0;
+
+static void statResetCsr(StatCursor *pCsr){
+  int i;
+  sqlite3_reset(pCsr->pStmt);
+  for(i=0; i<ArraySize(pCsr->aPage); i++){
+    statClearPage(&pCsr->aPage[i]);
+  }
+  pCsr->iPage = 0;
+  sqlite3_free(pCsr->zPath);
+  pCsr->zPath = 0;
+  pCsr->isEof = 0;
 }
 
 /*
-** Install the diff hooks on the session object passed as the only
-** argument.
+** Close a statvfs cursor.
 */
-static void sessionDiffHooks(
-  sqlite3_session *pSession,
-  SessionDiffCtx *pDiffCtx
-){
-  pSession->hook.pCtx = (void*)pDiffCtx;
-  pSession->hook.xOld = sessionDiffOld;
-  pSession->hook.xNew = sessionDiffNew;
-  pSession->hook.xCount = sessionDiffCount;
-  pSession->hook.xDepth = sessionDiffDepth;
+static int statClose(sqlite3_vtab_cursor *pCursor){
+  StatCursor *pCsr = (StatCursor *)pCursor;
+  statResetCsr(pCsr);
+  sqlite3_finalize(pCsr->pStmt);
+  sqlite3_free(pCsr);
+  return SQLITE_OK;
 }
 
-static char *sessionExprComparePK(
-  int nCol,
-  const char *zDb1, const char *zDb2, 
-  const char *zTab,
-  const char **azCol, u8 *abPK
+static void getLocalPayload(
+  int nUsable,                    /* Usable bytes per page */
+  u8 flags,                       /* Page flags */
+  int nTotal,                     /* Total record (payload) size */
+  int *pnLocal                    /* OUT: Bytes stored locally */
 ){
-  int i;
-  const char *zSep = "";
-  char *zRet = 0;
-
-  for(i=0; i<nCol; i++){
-    if( abPK[i] ){
-      zRet = sqlite3_mprintf("%z%s\"%w\".\"%w\".\"%w\"=\"%w\".\"%w\".\"%w\"",
-          zRet, zSep, zDb1, zTab, azCol[i], zDb2, zTab, azCol[i]
-      );
-      zSep = " AND ";
-      if( zRet==0 ) break;
-    }
+  int nLocal;
+  int nMinLocal;
+  int nMaxLocal;
+  if( flags==0x0D ){              /* Table leaf node */
+    nMinLocal = (nUsable - 12) * 32 / 255 - 23;
+    nMaxLocal = nUsable - 35;
+  }else{                          /* Index interior and leaf nodes */
+    nMinLocal = (nUsable - 12) * 32 / 255 - 23;
+    nMaxLocal = (nUsable - 12) * 64 / 255 - 23;
   }
 
-  return zRet;
+  nLocal = nMinLocal + (nTotal - nMinLocal) % (nUsable - 4);
+  if( nLocal>nMaxLocal ) nLocal = nMinLocal;
+  *pnLocal = nLocal;
 }
 
-static char *sessionExprCompareOther(
-  int nCol,
-  const char *zDb1, const char *zDb2, 
-  const char *zTab,
-  const char **azCol, u8 *abPK
-){
-  int i;
-  const char *zSep = "";
-  char *zRet = 0;
-  int bHave = 0;
+static int statDecodePage(Btree *pBt, StatPage *p){
+  int nUnused;
+  int iOff;
+  int nHdr;
+  int isLeaf;
+  int szPage;
 
-  for(i=0; i<nCol; i++){
-    if( abPK[i]==0 ){
-      bHave = 1;
-      zRet = sqlite3_mprintf(
-          "%z%s\"%w\".\"%w\".\"%w\" IS NOT \"%w\".\"%w\".\"%w\"",
-          zRet, zSep, zDb1, zTab, azCol[i], zDb2, zTab, azCol[i]
-      );
-      zSep = " OR ";
-      if( zRet==0 ) break;
-    }
-  }
+  u8 *aData = sqlite3PagerGetData(p->pPg);
+  u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0];
 
-  if( bHave==0 ){
-    assert( zRet==0 );
-    zRet = sqlite3_mprintf("0");
+  p->flags = aHdr[0];
+  p->nCell = get2byte(&aHdr[3]);
+  p->nMxPayload = 0;
+
+  isLeaf = (p->flags==0x0A || p->flags==0x0D);
+  nHdr = 12 - isLeaf*4 + (p->iPgno==1)*100;
+
+  nUnused = get2byte(&aHdr[5]) - nHdr - 2*p->nCell;
+  nUnused += (int)aHdr[7];
+  iOff = get2byte(&aHdr[1]);
+  while( iOff ){
+    nUnused += get2byte(&aData[iOff+2]);
+    iOff = get2byte(&aData[iOff]);
   }
+  p->nUnused = nUnused;
+  p->iRightChildPg = isLeaf ? 0 : sqlite3Get4byte(&aHdr[8]);
+  szPage = sqlite3BtreeGetPageSize(pBt);
 
-  return zRet;
-}
+  if( p->nCell ){
+    int i;                        /* Used to iterate through cells */
+    int nUsable;                  /* Usable bytes per page */
 
-static char *sessionSelectFindNew(
-  int nCol,
-  const char *zDb1,      /* Pick rows in this db only */
-  const char *zDb2,      /* But not in this one */
-  const char *zTbl,      /* Table name */
-  const char *zExpr
-){
-  char *zRet = sqlite3_mprintf(
-      "SELECT * FROM \"%w\".\"%w\" WHERE NOT EXISTS ("
-      "  SELECT 1 FROM \"%w\".\"%w\" WHERE %s"
-      ")",
-      zDb1, zTbl, zDb2, zTbl, zExpr
-  );
-  return zRet;
-}
+    sqlite3BtreeEnter(pBt);
+    nUsable = szPage - sqlite3BtreeGetReserveNoMutex(pBt);
+    sqlite3BtreeLeave(pBt);
+    p->aCell = sqlite3_malloc64((p->nCell+1) * sizeof(StatCell));
+    if( p->aCell==0 ) return SQLITE_NOMEM_BKPT;
+    memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell));
 
-static int sessionDiffFindNew(
-  int op,
-  sqlite3_session *pSession,
-  SessionTable *pTab,
-  const char *zDb1,
-  const char *zDb2,
-  char *zExpr
-){
-  int rc = SQLITE_OK;
-  char *zStmt = sessionSelectFindNew(pTab->nCol, zDb1, zDb2, pTab->zName,zExpr);
+    for(i=0; i<p->nCell; i++){
+      StatCell *pCell = &p->aCell[i];
 
-  if( zStmt==0 ){
-    rc = SQLITE_NOMEM;
-  }else{
-    sqlite3_stmt *pStmt;
-    rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0);
-    if( rc==SQLITE_OK ){
-      SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx;
-      pDiffCtx->pStmt = pStmt;
-      pDiffCtx->nOldOff = 0;
-      while( SQLITE_ROW==sqlite3_step(pStmt) ){
-        sessionPreupdateOneChange(op, pSession, pTab);
+      iOff = get2byte(&aData[nHdr+i*2]);
+      if( !isLeaf ){
+        pCell->iChildPg = sqlite3Get4byte(&aData[iOff]);
+        iOff += 4;
+      }
+      if( p->flags==0x05 ){
+        /* A table interior node. nPayload==0. */
+      }else{
+        u32 nPayload;             /* Bytes of payload total (local+overflow) */
+        int nLocal;               /* Bytes of payload stored locally */
+        iOff += getVarint32(&aData[iOff], nPayload);
+        if( p->flags==0x0D ){
+          u64 dummy;
+          iOff += sqlite3GetVarint(&aData[iOff], &dummy);
+        }
+        if( nPayload>(u32)p->nMxPayload ) p->nMxPayload = nPayload;
+        getLocalPayload(nUsable, p->flags, nPayload, &nLocal);
+        pCell->nLocal = nLocal;
+        assert( nLocal>=0 );
+        assert( nPayload>=(u32)nLocal );
+        assert( nLocal<=(nUsable-35) );
+        if( nPayload>(u32)nLocal ){
+          int j;
+          int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4);
+          pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
+          pCell->nOvfl = nOvfl;
+          pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl);
+          if( pCell->aOvfl==0 ) return SQLITE_NOMEM_BKPT;
+          pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]);
+          for(j=1; j<nOvfl; j++){
+            int rc;
+            u32 iPrev = pCell->aOvfl[j-1];
+            DbPage *pPg = 0;
+            rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPrev, &pPg, 0);
+            if( rc!=SQLITE_OK ){
+              assert( pPg==0 );
+              return rc;
+            } 
+            pCell->aOvfl[j] = sqlite3Get4byte(sqlite3PagerGetData(pPg));
+            sqlite3PagerUnref(pPg);
+          }
+        }
       }
-      rc = sqlite3_finalize(pStmt);
     }
-    sqlite3_free(zStmt);
   }
 
-  return rc;
+  return SQLITE_OK;
 }
 
-static int sessionDiffFindModified(
-  sqlite3_session *pSession, 
-  SessionTable *pTab, 
-  const char *zFrom, 
-  const char *zExpr
-){
-  int rc = SQLITE_OK;
+/*
+** Populate the pCsr->iOffset and pCsr->szPage member variables. Based on
+** the current value of pCsr->iPageno.
+*/
+static void statSizeAndOffset(StatCursor *pCsr){
+  StatTable *pTab = (StatTable *)((sqlite3_vtab_cursor *)pCsr)->pVtab;
+  Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
+  Pager *pPager = sqlite3BtreePager(pBt);
+  sqlite3_file *fd;
+  sqlite3_int64 x[2];
 
-  char *zExpr2 = sessionExprCompareOther(pTab->nCol,
-      pSession->zDb, zFrom, pTab->zName, pTab->azCol, pTab->abPK
-  );
-  if( zExpr2==0 ){
-    rc = SQLITE_NOMEM;
-  }else{
-    char *zStmt = sqlite3_mprintf(
-        "SELECT * FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)",
-        pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2
-    );
-    if( zStmt==0 ){
-      rc = SQLITE_NOMEM;
-    }else{
-      sqlite3_stmt *pStmt;
-      rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0);
+  /* The default page size and offset */
+  pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
+  pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1);
 
-      if( rc==SQLITE_OK ){
-        SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx;
-        pDiffCtx->pStmt = pStmt;
-        pDiffCtx->nOldOff = pTab->nCol;
-        while( SQLITE_ROW==sqlite3_step(pStmt) ){
-          sessionPreupdateOneChange(SQLITE_UPDATE, pSession, pTab);
-        }
-        rc = sqlite3_finalize(pStmt);
-      }
-      sqlite3_free(zStmt);
-    }
+  /* If connected to a ZIPVFS backend, override the page size and
+  ** offset with actual values obtained from ZIPVFS.
+  */
+  fd = sqlite3PagerFile(pPager);
+  x[0] = pCsr->iPageno;
+  if( sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){
+    pCsr->iOffset = x[0];
+    pCsr->szPage = (int)x[1];
   }
-
-  return rc;
 }
 
-SQLITE_API int sqlite3session_diff(
-  sqlite3_session *pSession,
-  const char *zFrom,
-  const char *zTbl,
-  char **pzErrMsg
-){
-  const char *zDb = pSession->zDb;
-  int rc = pSession->rc;
-  SessionDiffCtx d;
-
-  memset(&d, 0, sizeof(d));
-  sessionDiffHooks(pSession, &d);
+/*
+** Move a statvfs cursor to the next entry in the file.
+*/
+static int statNext(sqlite3_vtab_cursor *pCursor){
+  int rc;
+  int nPayload;
+  char *z;
+  StatCursor *pCsr = (StatCursor *)pCursor;
+  StatTable *pTab = (StatTable *)pCursor->pVtab;
+  Btree *pBt = pTab->db->aDb[pCsr->iDb].pBt;
+  Pager *pPager = sqlite3BtreePager(pBt);
 
-  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
-  if( pzErrMsg ) *pzErrMsg = 0;
-  if( rc==SQLITE_OK ){
-    char *zExpr = 0;
-    sqlite3 *db = pSession->db;
-    SessionTable *pTo;            /* Table zTbl */
+  sqlite3_free(pCsr->zPath);
+  pCsr->zPath = 0;
 
-    /* Locate and if necessary initialize the target table object */
-    rc = sessionFindTable(pSession, zTbl, &pTo);
-    if( pTo==0 ) goto diff_out;
-    if( sessionInitTable(pSession, pTo) ){
-      rc = pSession->rc;
-      goto diff_out;
+statNextRestart:
+  if( pCsr->aPage[0].pPg==0 ){
+    rc = sqlite3_step(pCsr->pStmt);
+    if( rc==SQLITE_ROW ){
+      int nPage;
+      u32 iRoot = (u32)sqlite3_column_int64(pCsr->pStmt, 1);
+      sqlite3PagerPagecount(pPager, &nPage);
+      if( nPage==0 ){
+        pCsr->isEof = 1;
+        return sqlite3_reset(pCsr->pStmt);
+      }
+      rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg, 0);
+      pCsr->aPage[0].iPgno = iRoot;
+      pCsr->aPage[0].iCell = 0;
+      pCsr->aPage[0].zPath = z = sqlite3_mprintf("/");
+      pCsr->iPage = 0;
+      if( z==0 ) rc = SQLITE_NOMEM_BKPT;
+    }else{
+      pCsr->isEof = 1;
+      return sqlite3_reset(pCsr->pStmt);
     }
+  }else{
 
-    /* Check the table schemas match */
-    if( rc==SQLITE_OK ){
-      int bHasPk = 0;
-      int bMismatch = 0;
-      int nCol;                   /* Columns in zFrom.zTbl */
-      u8 *abPK;
-      const char **azCol = 0;
-      rc = sessionTableInfo(db, zFrom, zTbl, &nCol, 0, &azCol, &abPK);
-      if( rc==SQLITE_OK ){
-        if( pTo->nCol!=nCol ){
-          bMismatch = 1;
+    /* Page p itself has already been visited. */
+    StatPage *p = &pCsr->aPage[pCsr->iPage];
+
+    while( p->iCell<p->nCell ){
+      StatCell *pCell = &p->aCell[p->iCell];
+      if( pCell->iOvfl<pCell->nOvfl ){
+        int nUsable;
+        sqlite3BtreeEnter(pBt);
+        nUsable = sqlite3BtreeGetPageSize(pBt) - 
+                        sqlite3BtreeGetReserveNoMutex(pBt);
+        sqlite3BtreeLeave(pBt);
+        pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
+        pCsr->iPageno = pCell->aOvfl[pCell->iOvfl];
+        pCsr->zPagetype = "overflow";
+        pCsr->nCell = 0;
+        pCsr->nMxPayload = 0;
+        pCsr->zPath = z = sqlite3_mprintf(
+            "%s%.3x+%.6x", p->zPath, p->iCell, pCell->iOvfl
+        );
+        if( pCell->iOvfl<pCell->nOvfl-1 ){
+          pCsr->nUnused = 0;
+          pCsr->nPayload = nUsable - 4;
         }else{
-          int i;
-          for(i=0; i<nCol; i++){
-            if( pTo->abPK[i]!=abPK[i] ) bMismatch = 1;
-            if( sqlite3_stricmp(azCol[i], pTo->azCol[i]) ) bMismatch = 1;
-            if( abPK[i] ) bHasPk = 1;
-          }
+          pCsr->nPayload = pCell->nLastOvfl;
+          pCsr->nUnused = nUsable - 4 - pCsr->nPayload;
         }
+        pCell->iOvfl++;
+        statSizeAndOffset(pCsr);
+        return z==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK;
       }
-      sqlite3_free((char*)azCol);
-      if( bMismatch ){
-        *pzErrMsg = sqlite3_mprintf("table schemas do not match");
-        rc = SQLITE_SCHEMA;
-      }
-      if( bHasPk==0 ){
-        /* Ignore tables with no primary keys */
-        goto diff_out;
-      }
+      if( p->iRightChildPg ) break;
+      p->iCell++;
     }
 
-    if( rc==SQLITE_OK ){
-      zExpr = sessionExprComparePK(pTo->nCol, 
-          zDb, zFrom, pTo->zName, pTo->azCol, pTo->abPK
-      );
+    if( !p->iRightChildPg || p->iCell>p->nCell ){
+      statClearPage(p);
+      if( pCsr->iPage==0 ) return statNext(pCursor);
+      pCsr->iPage--;
+      goto statNextRestart; /* Tail recursion */
     }
+    pCsr->iPage++;
+    assert( p==&pCsr->aPage[pCsr->iPage-1] );
 
-    /* Find new rows */
-    if( rc==SQLITE_OK ){
-      rc = sessionDiffFindNew(SQLITE_INSERT, pSession, pTo, zDb, zFrom, zExpr);
+    if( p->iCell==p->nCell ){
+      p[1].iPgno = p->iRightChildPg;
+    }else{
+      p[1].iPgno = p->aCell[p->iCell].iChildPg;
     }
+    rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg, 0);
+    p[1].iCell = 0;
+    p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
+    p->iCell++;
+    if( z==0 ) rc = SQLITE_NOMEM_BKPT;
+  }
 
-    /* Find old rows */
-    if( rc==SQLITE_OK ){
-      rc = sessionDiffFindNew(SQLITE_DELETE, pSession, pTo, zFrom, zDb, zExpr);
-    }
 
-    /* Find modified rows */
+  /* Populate the StatCursor fields with the values to be returned
+  ** by the xColumn() and xRowid() methods.
+  */
+  if( rc==SQLITE_OK ){
+    int i;
+    StatPage *p = &pCsr->aPage[pCsr->iPage];
+    pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
+    pCsr->iPageno = p->iPgno;
+
+    rc = statDecodePage(pBt, p);
     if( rc==SQLITE_OK ){
-      rc = sessionDiffFindModified(pSession, pTo, zFrom, zExpr);
-    }
+      statSizeAndOffset(pCsr);
 
-    sqlite3_free(zExpr);
+      switch( p->flags ){
+        case 0x05:             /* table internal */
+        case 0x02:             /* index internal */
+          pCsr->zPagetype = "internal";
+          break;
+        case 0x0D:             /* table leaf */
+        case 0x0A:             /* index leaf */
+          pCsr->zPagetype = "leaf";
+          break;
+        default:
+          pCsr->zPagetype = "corrupted";
+          break;
+      }
+      pCsr->nCell = p->nCell;
+      pCsr->nUnused = p->nUnused;
+      pCsr->nMxPayload = p->nMxPayload;
+      pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath);
+      if( z==0 ) rc = SQLITE_NOMEM_BKPT;
+      nPayload = 0;
+      for(i=0; i<p->nCell; i++){
+        nPayload += p->aCell[i].nLocal;
+      }
+      pCsr->nPayload = nPayload;
+    }
   }
 
- diff_out:
-  sessionPreupdateHooks(pSession);
-  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
   return rc;
 }
 
-/*
-** Create a session object. This session object will record changes to
-** database zDb attached to connection db.
-*/
-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 */
+static int statEof(sqlite3_vtab_cursor *pCursor){
+  StatCursor *pCsr = (StatCursor *)pCursor;
+  return pCsr->isEof;
+}
+
+static int statFilter(
+  sqlite3_vtab_cursor *pCursor, 
+  int idxNum, const char *idxStr,
+  int argc, sqlite3_value **argv
 ){
-  sqlite3_session *pNew;          /* Newly allocated session object */
-  sqlite3_session *pOld;          /* Session object already attached to db */
-  int nDb = sqlite3Strlen30(zDb); /* Length of zDb in bytes */
+  StatCursor *pCsr = (StatCursor *)pCursor;
+  StatTable *pTab = (StatTable*)(pCursor->pVtab);
+  char *zSql;
+  int rc = SQLITE_OK;
+  char *zMaster;
 
-  /* Zero the output value in case an error occurs. */
-  *ppSession = 0;
+  if( idxNum==1 ){
+    const char *zDbase = (const char*)sqlite3_value_text(argv[0]);
+    pCsr->iDb = sqlite3FindDbName(pTab->db, zDbase);
+    if( pCsr->iDb<0 ){
+      sqlite3_free(pCursor->pVtab->zErrMsg);
+      pCursor->pVtab->zErrMsg = sqlite3_mprintf("no such schema: %s", zDbase);
+      return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM_BKPT;
+    }
+  }else{
+    pCsr->iDb = pTab->iDb;
+  }
+  statResetCsr(pCsr);
+  sqlite3_finalize(pCsr->pStmt);
+  pCsr->pStmt = 0;
+  zMaster = pCsr->iDb==1 ? "sqlite_temp_master" : "sqlite_master";
+  zSql = sqlite3_mprintf(
+      "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
+      "  UNION ALL  "
+      "SELECT name, rootpage, type"
+      "  FROM \"%w\".%s WHERE rootpage!=0"
+      "  ORDER BY name", pTab->db->aDb[pCsr->iDb].zDbSName, zMaster);
+  if( zSql==0 ){
+    return SQLITE_NOMEM_BKPT;
+  }else{
+    rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
+    sqlite3_free(zSql);
+  }
 
-  /* Allocate and populate the new session object. */
-  pNew = (sqlite3_session *)sqlite3_malloc(sizeof(sqlite3_session) + nDb + 1);
-  if( !pNew ) return SQLITE_NOMEM;
-  memset(pNew, 0, sizeof(sqlite3_session));
-  pNew->db = db;
-  pNew->zDb = (char *)&pNew[1];
-  pNew->bEnable = 1;
-  memcpy(pNew->zDb, zDb, nDb+1);
-  sessionPreupdateHooks(pNew);
+  if( rc==SQLITE_OK ){
+    rc = statNext(pCursor);
+  }
+  return rc;
+}
 
-  /* Add the new session object to the linked list of session objects 
-  ** attached to database handle $db. Do this under the cover of the db
-  ** handle mutex.  */
-  sqlite3_mutex_enter(sqlite3_db_mutex(db));
-  pOld = (sqlite3_session*)sqlite3_preupdate_hook(db, xPreUpdate, (void*)pNew);
-  pNew->pNext = pOld;
-  sqlite3_mutex_leave(sqlite3_db_mutex(db));
+static int statColumn(
+  sqlite3_vtab_cursor *pCursor, 
+  sqlite3_context *ctx, 
+  int i
+){
+  StatCursor *pCsr = (StatCursor *)pCursor;
+  switch( i ){
+    case 0:            /* name */
+      sqlite3_result_text(ctx, pCsr->zName, -1, SQLITE_TRANSIENT);
+      break;
+    case 1:            /* path */
+      sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT);
+      break;
+    case 2:            /* pageno */
+      sqlite3_result_int64(ctx, pCsr->iPageno);
+      break;
+    case 3:            /* pagetype */
+      sqlite3_result_text(ctx, pCsr->zPagetype, -1, SQLITE_STATIC);
+      break;
+    case 4:            /* ncell */
+      sqlite3_result_int(ctx, pCsr->nCell);
+      break;
+    case 5:            /* payload */
+      sqlite3_result_int(ctx, pCsr->nPayload);
+      break;
+    case 6:            /* unused */
+      sqlite3_result_int(ctx, pCsr->nUnused);
+      break;
+    case 7:            /* mx_payload */
+      sqlite3_result_int(ctx, pCsr->nMxPayload);
+      break;
+    case 8:            /* pgoffset */
+      sqlite3_result_int64(ctx, pCsr->iOffset);
+      break;
+    case 9:            /* pgsize */
+      sqlite3_result_int(ctx, pCsr->szPage);
+      break;
+    default: {          /* schema */
+      sqlite3 *db = sqlite3_context_db_handle(ctx);
+      int iDb = pCsr->iDb;
+      sqlite3_result_text(ctx, db->aDb[iDb].zDbSName, -1, SQLITE_STATIC);
+      break;
+    }
+  }
+  return SQLITE_OK;
+}
 
-  *ppSession = pNew;
+static int statRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
+  StatCursor *pCsr = (StatCursor *)pCursor;
+  *pRowid = pCsr->iPageno;
   return SQLITE_OK;
 }
 
 /*
-** Free the list of table objects passed as the first argument. The contents
-** of the changed-rows hash tables are also deleted.
+** Invoke this routine to register the "dbstat" virtual table module
+*/
+SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){
+  static sqlite3_module dbstat_module = {
+    0,                            /* iVersion */
+    statConnect,                  /* xCreate */
+    statConnect,                  /* xConnect */
+    statBestIndex,                /* xBestIndex */
+    statDisconnect,               /* xDisconnect */
+    statDisconnect,               /* xDestroy */
+    statOpen,                     /* xOpen - open a cursor */
+    statClose,                    /* xClose - close a cursor */
+    statFilter,                   /* xFilter - configure scan constraints */
+    statNext,                     /* xNext - advance a cursor */
+    statEof,                      /* xEof - check for end of scan */
+    statColumn,                   /* xColumn - read data */
+    statRowid,                    /* xRowid - read data */
+    0,                            /* xUpdate */
+    0,                            /* xBegin */
+    0,                            /* xSync */
+    0,                            /* xCommit */
+    0,                            /* xRollback */
+    0,                            /* xFindMethod */
+    0,                            /* xRename */
+    0,                            /* xSavepoint */
+    0,                            /* xRelease */
+    0,                            /* xRollbackTo */
+  };
+  return sqlite3_create_module(db, "dbstat", &dbstat_module, 0);
+}
+#elif defined(SQLITE_ENABLE_DBSTAT_VTAB)
+SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; }
+#endif /* SQLITE_ENABLE_DBSTAT_VTAB */
+
+/************** End of dbstat.c **********************************************/
+/************** Begin file dbpage.c ******************************************/
+/*
+** 2017-10-11
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file contains an implementation of the "sqlite_dbpage" virtual table.
+**
+** The sqlite_dbpage virtual table is used to read or write whole raw
+** pages of the database file.  The pager interface is used so that 
+** uncommitted changes and changes recorded in the WAL file are correctly
+** retrieved.
+**
+** Usage example:
+**
+**    SELECT data FROM sqlite_dbpage('aux1') WHERE pgno=123;
+**
+** This is an eponymous virtual table so it does not need to be created before
+** use.  The optional argument to the sqlite_dbpage() table name is the
+** schema for the database file that is to be read.  The default schema is
+** "main".
+**
+** The data field of sqlite_dbpage table can be updated.  The new
+** value must be a BLOB which is the correct page size, otherwise the
+** update fails.  Rows may not be deleted or inserted.
 */
-static void sessionDeleteTable(SessionTable *pList){
-  SessionTable *pNext;
-  SessionTable *pTab;
 
-  for(pTab=pList; pTab; pTab=pNext){
-    int i;
-    pNext = pTab->pNext;
-    for(i=0; i<pTab->nChange; i++){
-      SessionChange *p;
-      SessionChange *pNextChange;
-      for(p=pTab->apChange[i]; p; p=pNextChange){
-        pNextChange = p->pNext;
-        sqlite3_free(p);
-      }
-    }
-    sqlite3_free((char*)pTab->azCol);  /* cast works around VC++ bug */
-    sqlite3_free(pTab->apChange);
-    sqlite3_free(pTab);
-  }
-}
+/* #include "sqliteInt.h"   ** Requires access to internal data structures ** */
+#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
+    && !defined(SQLITE_OMIT_VIRTUALTABLE)
 
-/*
-** Delete a session object previously allocated using sqlite3session_create().
-*/
-SQLITE_API void sqlite3session_delete(sqlite3_session *pSession){
-  sqlite3 *db = pSession->db;
-  sqlite3_session *pHead;
-  sqlite3_session **pp;
+typedef struct DbpageTable DbpageTable;
+typedef struct DbpageCursor DbpageCursor;
 
-  /* Unlink the session from the linked list of sessions attached to the
-  ** database handle. Hold the db mutex while doing so.  */
-  sqlite3_mutex_enter(sqlite3_db_mutex(db));
-  pHead = (sqlite3_session*)sqlite3_preupdate_hook(db, 0, 0);
-  for(pp=&pHead; ALWAYS((*pp)!=0); pp=&((*pp)->pNext)){
-    if( (*pp)==pSession ){
-      *pp = (*pp)->pNext;
-      if( pHead ) sqlite3_preupdate_hook(db, xPreUpdate, (void*)pHead);
-      break;
-    }
-  }
-  sqlite3_mutex_leave(sqlite3_db_mutex(db));
-  sqlite3ValueFree(pSession->pZeroBlob);
+struct DbpageCursor {
+  sqlite3_vtab_cursor base;       /* Base class.  Must be first */
+  int pgno;                       /* Current page number */
+  int mxPgno;                     /* Last page to visit on this scan */
+  Pager *pPager;                  /* Pager being read/written */
+  DbPage *pPage1;                 /* Page 1 of the database */
+  int iDb;                        /* Index of database to analyze */
+  int szPage;                     /* Size of each page in bytes */
+};
 
-  /* Delete all attached table objects. And the contents of their 
-  ** associated hash-tables. */
-  sessionDeleteTable(pSession->pTable);
+struct DbpageTable {
+  sqlite3_vtab base;              /* Base class.  Must be first */
+  sqlite3 *db;                    /* The database */
+};
+
+/* Columns */
+#define DBPAGE_COLUMN_PGNO    0
+#define DBPAGE_COLUMN_DATA    1
+#define DBPAGE_COLUMN_SCHEMA  2
 
-  /* Free the session object itself. */
-  sqlite3_free(pSession);
-}
 
-/*
-** Set a table filter on a Session Object.
-*/
-SQLITE_API void sqlite3session_table_filter(
-  sqlite3_session *pSession, 
-  int(*xFilter)(void*, const char*),
-  void *pCtx                      /* First argument passed to xFilter */
-){
-  pSession->bAutoAttach = 1;
-  pSession->pFilterCtx = pCtx;
-  pSession->xTableFilter = xFilter;
-}
 
 /*
-** Attach a table to a session. All subsequent changes made to the table
-** while the session object is enabled will be recorded.
-**
-** Only tables that have a PRIMARY KEY defined may be attached. It does
-** not matter if the PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias)
-** or not.
+** Connect to or create a dbpagevfs virtual table.
 */
-SQLITE_API int sqlite3session_attach(
-  sqlite3_session *pSession,      /* Session object */
-  const char *zName               /* Table name */
+static int dbpageConnect(
+  sqlite3 *db,
+  void *pAux,
+  int argc, const char *const*argv,
+  sqlite3_vtab **ppVtab,
+  char **pzErr
 ){
+  DbpageTable *pTab = 0;
   int rc = SQLITE_OK;
-  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
 
-  if( !zName ){
-    pSession->bAutoAttach = 1;
-  }else{
-    SessionTable *pTab;           /* New table object (if required) */
-    int nName;                    /* Number of bytes in string zName */
-
-    /* First search for an existing entry. If one is found, this call is
-    ** a no-op. Return early. */
-    nName = sqlite3Strlen30(zName);
-    for(pTab=pSession->pTable; pTab; pTab=pTab->pNext){
-      if( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ) break;
-    }
+  rc = sqlite3_declare_vtab(db, 
+          "CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
+  if( rc==SQLITE_OK ){
+    pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable));
+    if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
+  }
 
-    if( !pTab ){
-      /* Allocate new SessionTable object. */
-      pTab = (SessionTable *)sqlite3_malloc(sizeof(SessionTable) + nName + 1);
-      if( !pTab ){
-        rc = SQLITE_NOMEM;
-      }else{
-        /* Populate the new SessionTable object and link it into the list.
-        ** The new object must be linked onto the end of the list, not 
-        ** simply added to the start of it in order to ensure that tables
-        ** appear in the correct order when a changeset or patchset is
-        ** eventually generated. */
-        SessionTable **ppTab;
-        memset(pTab, 0, sizeof(SessionTable));
-        pTab->zName = (char *)&pTab[1];
-        memcpy(pTab->zName, zName, nName+1);
-        for(ppTab=&pSession->pTable; *ppTab; ppTab=&(*ppTab)->pNext);
-        *ppTab = pTab;
-      }
-    }
+  assert( rc==SQLITE_OK || pTab==0 );
+  if( rc==SQLITE_OK ){
+    memset(pTab, 0, sizeof(DbpageTable));
+    pTab->db = db;
   }
 
-  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
+  *ppVtab = (sqlite3_vtab*)pTab;
   return rc;
 }
 
 /*
-** Ensure that there is room in the buffer to append nByte bytes of data.
-** If not, use sqlite3_realloc() to grow the buffer so that there is.
-**
-** If successful, return zero. Otherwise, if an OOM condition is encountered,
-** set *pRc to SQLITE_NOMEM and return non-zero.
+** Disconnect from or destroy a dbpagevfs virtual table.
 */
-static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){
-  if( *pRc==SQLITE_OK && p->nAlloc-p->nBuf<nByte ){
-    u8 *aNew;
-    int nNew = p->nAlloc ? p->nAlloc : 128;
-    do {
-      nNew = nNew*2;
-    }while( nNew<(p->nBuf+nByte) );
-
-    aNew = (u8 *)sqlite3_realloc(p->aBuf, nNew);
-    if( 0==aNew ){
-      *pRc = SQLITE_NOMEM;
-    }else{
-      p->aBuf = aNew;
-      p->nAlloc = nNew;
-    }
-  }
-  return (*pRc!=SQLITE_OK);
+static int dbpageDisconnect(sqlite3_vtab *pVtab){
+  sqlite3_free(pVtab);
+  return SQLITE_OK;
 }
 
 /*
-** Append the value passed as the second argument to the buffer passed
-** as the first.
+** idxNum:
 **
-** This function is a no-op if *pRc is non-zero when it is called.
-** Otherwise, if an error occurs, *pRc is set to an SQLite error code
-** before returning.
+**     0     schema=main, full table scan
+**     1     schema=main, pgno=?1
+**     2     schema=?1, full table scan
+**     3     schema=?1, pgno=?2
 */
-static void sessionAppendValue(SessionBuffer *p, sqlite3_value *pVal, int *pRc){
-  int rc = *pRc;
-  if( rc==SQLITE_OK ){
-    int nByte = 0;
-    rc = sessionSerializeValue(0, pVal, &nByte);
-    sessionBufferGrow(p, nByte, &rc);
-    if( rc==SQLITE_OK ){
-      rc = sessionSerializeValue(&p->aBuf[p->nBuf], pVal, 0);
-      p->nBuf += nByte;
-    }else{
-      *pRc = rc;
+static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
+  int i;
+  int iPlan = 0;
+
+  /* If there is a schema= constraint, it must be honored.  Report a
+  ** ridiculously large estimated cost if the schema= constraint is
+  ** unavailable
+  */
+  for(i=0; i<pIdxInfo->nConstraint; i++){
+    struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
+    if( p->iColumn!=DBPAGE_COLUMN_SCHEMA ) continue;
+    if( p->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
+    if( !p->usable ){
+      /* No solution.  Use the default SQLITE_BIG_DBL cost */
+      pIdxInfo->estimatedRows = 0x7fffffff;
+      return SQLITE_OK;
     }
+    iPlan = 2;
+    pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+    pIdxInfo->aConstraintUsage[i].omit = 1;
+    break;
   }
-}
 
-/*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is 
-** called. Otherwise, append a single byte to the buffer. 
-**
-** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
-** returning.
-*/
-static void sessionAppendByte(SessionBuffer *p, u8 v, int *pRc){
-  if( 0==sessionBufferGrow(p, 1, pRc) ){
-    p->aBuf[p->nBuf++] = v;
-  }
-}
+  /* If we reach this point, it means that either there is no schema=
+  ** constraint (in which case we use the "main" schema) or else the
+  ** schema constraint was accepted.  Lower the estimated cost accordingly
+  */
+  pIdxInfo->estimatedCost = 1.0e6;
 
-/*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is 
-** called. Otherwise, append a single varint to the buffer. 
-**
-** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
-** returning.
-*/
-static void sessionAppendVarint(SessionBuffer *p, int v, int *pRc){
-  if( 0==sessionBufferGrow(p, 9, pRc) ){
-    p->nBuf += sessionVarintPut(&p->aBuf[p->nBuf], v);
+  /* Check for constraints against pgno */
+  for(i=0; i<pIdxInfo->nConstraint; i++){
+    struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
+    if( p->usable && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
+      pIdxInfo->estimatedRows = 1;
+      pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
+      pIdxInfo->estimatedCost = 1.0;
+      pIdxInfo->aConstraintUsage[i].argvIndex = iPlan ? 2 : 1;
+      pIdxInfo->aConstraintUsage[i].omit = 1;
+      iPlan |= 1;
+      break;
+    }
   }
-}
+  pIdxInfo->idxNum = iPlan;
 
-/*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is 
-** called. Otherwise, append a blob of data to the buffer. 
-**
-** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
-** returning.
-*/
-static void sessionAppendBlob(
-  SessionBuffer *p, 
-  const u8 *aBlob, 
-  int nBlob, 
-  int *pRc
-){
-  if( nBlob>0 && 0==sessionBufferGrow(p, nBlob, pRc) ){
-    memcpy(&p->aBuf[p->nBuf], aBlob, nBlob);
-    p->nBuf += nBlob;
+  if( pIdxInfo->nOrderBy>=1
+   && pIdxInfo->aOrderBy[0].iColumn<=0
+   && pIdxInfo->aOrderBy[0].desc==0
+  ){
+    pIdxInfo->orderByConsumed = 1;
   }
+  return SQLITE_OK;
 }
 
 /*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is 
-** called. Otherwise, append a string to the buffer. All bytes in the string
-** up to (but not including) the nul-terminator are written to the buffer.
-**
-** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
-** returning.
+** Open a new dbpagevfs cursor.
 */
-static void sessionAppendStr(
-  SessionBuffer *p, 
-  const char *zStr, 
-  int *pRc
-){
-  int nStr = sqlite3Strlen30(zStr);
-  if( 0==sessionBufferGrow(p, nStr, pRc) ){
-    memcpy(&p->aBuf[p->nBuf], zStr, nStr);
-    p->nBuf += nStr;
+static int dbpageOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
+  DbpageCursor *pCsr;
+
+  pCsr = (DbpageCursor *)sqlite3_malloc64(sizeof(DbpageCursor));
+  if( pCsr==0 ){
+    return SQLITE_NOMEM_BKPT;
+  }else{
+    memset(pCsr, 0, sizeof(DbpageCursor));
+    pCsr->base.pVtab = pVTab;
+    pCsr->pgno = -1;
   }
+
+  *ppCursor = (sqlite3_vtab_cursor *)pCsr;
+  return SQLITE_OK;
 }
 
 /*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is 
-** called. Otherwise, append the string representation of integer iVal
-** to the buffer. No nul-terminator is written.
-**
-** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
-** returning.
+** Close a dbpagevfs cursor.
 */
-static void sessionAppendInteger(
-  SessionBuffer *p,               /* Buffer to append to */
-  int iVal,                       /* Value to write the string rep. of */
-  int *pRc                        /* IN/OUT: Error code */
-){
-  char aBuf[24];
-  sqlite3_snprintf(sizeof(aBuf)-1, aBuf, "%d", iVal);
-  sessionAppendStr(p, aBuf, pRc);
+static int dbpageClose(sqlite3_vtab_cursor *pCursor){
+  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+  if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1);
+  sqlite3_free(pCsr);
+  return SQLITE_OK;
 }
 
 /*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is 
-** called. Otherwise, append the string zStr enclosed in quotes (") and
-** with any embedded quote characters escaped to the buffer. No 
-** nul-terminator byte is written.
-**
-** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
-** returning.
+** Move a dbpagevfs cursor to the next entry in the file.
 */
-static void sessionAppendIdent(
-  SessionBuffer *p,               /* Buffer to a append to */
-  const char *zStr,               /* String to quote, escape and append */
-  int *pRc                        /* IN/OUT: Error code */
-){
-  int nStr = sqlite3Strlen30(zStr)*2 + 2 + 1;
-  if( 0==sessionBufferGrow(p, nStr, pRc) ){
-    char *zOut = (char *)&p->aBuf[p->nBuf];
-    const char *zIn = zStr;
-    *zOut++ = '"';
-    while( *zIn ){
-      if( *zIn=='"' ) *zOut++ = '"';
-      *zOut++ = *(zIn++);
-    }
-    *zOut++ = '"';
-    p->nBuf = (int)((u8 *)zOut - p->aBuf);
-  }
+static int dbpageNext(sqlite3_vtab_cursor *pCursor){
+  int rc = SQLITE_OK;
+  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+  pCsr->pgno++;
+  return rc;
 }
 
-/*
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
-** called. Otherwse, it appends the serialized version of the value stored
-** in column iCol of the row that SQL statement pStmt currently points
-** to to the buffer.
-*/
-static void sessionAppendCol(
-  SessionBuffer *p,               /* Buffer to append to */
-  sqlite3_stmt *pStmt,            /* Handle pointing to row containing value */
-  int iCol,                       /* Column to read value from */
-  int *pRc                        /* IN/OUT: Error code */
-){
-  if( *pRc==SQLITE_OK ){
-    int eType = sqlite3_column_type(pStmt, iCol);
-    sessionAppendByte(p, (u8)eType, pRc);
-    if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
-      sqlite3_int64 i;
-      u8 aBuf[8];
-      if( eType==SQLITE_INTEGER ){
-        i = sqlite3_column_int64(pStmt, iCol);
-      }else{
-        double r = sqlite3_column_double(pStmt, iCol);
-        memcpy(&i, &r, 8);
-      }
-      sessionPutI64(aBuf, i);
-      sessionAppendBlob(p, aBuf, 8, pRc);
-    }
-    if( eType==SQLITE_BLOB || eType==SQLITE_TEXT ){
-      u8 *z;
-      int nByte;
-      if( eType==SQLITE_BLOB ){
-        z = (u8 *)sqlite3_column_blob(pStmt, iCol);
-      }else{
-        z = (u8 *)sqlite3_column_text(pStmt, iCol);
-      }
-      nByte = sqlite3_column_bytes(pStmt, iCol);
-      if( z || (eType==SQLITE_BLOB && nByte==0) ){
-        sessionAppendVarint(p, nByte, pRc);
-        sessionAppendBlob(p, z, nByte, pRc);
-      }else{
-        *pRc = SQLITE_NOMEM;
-      }
-    }
-  }
+static int dbpageEof(sqlite3_vtab_cursor *pCursor){
+  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+  return pCsr->pgno > pCsr->mxPgno;
 }
 
 /*
+** idxNum:
 **
-** This function appends an update change to the buffer (see the comments 
-** under "CHANGESET FORMAT" at the top of the file). An update change 
-** consists of:
-**
-**   1 byte:  SQLITE_UPDATE (0x17)
-**   n bytes: old.* record (see RECORD FORMAT)
-**   m bytes: new.* record (see RECORD FORMAT)
-**
-** The SessionChange object passed as the third argument contains the
-** values that were stored in the row when the session began (the old.*
-** values). The statement handle passed as the second argument points
-** at the current version of the row (the new.* values).
-**
-** If all of the old.* values are equal to their corresponding new.* value
-** (i.e. nothing has changed), then no data at all is appended to the buffer.
+**     0     schema=main, full table scan
+**     1     schema=main, pgno=?1
+**     2     schema=?1, full table scan
+**     3     schema=?1, pgno=?2
 **
-** Otherwise, the old.* record contains all primary key values and the 
-** original values of any fields that have been modified. The new.* record 
-** contains the new values of only those fields that have been modified.
-*/ 
-static int sessionAppendUpdate(
-  SessionBuffer *pBuf,            /* Buffer to append to */
-  int bPatchset,                  /* True for "patchset", 0 for "changeset" */
-  sqlite3_stmt *pStmt,            /* Statement handle pointing at new row */
-  SessionChange *p,               /* Object containing old values */
-  u8 *abPK                        /* Boolean array - true for PK columns */
+** idxStr is not used
+*/
+static int dbpageFilter(
+  sqlite3_vtab_cursor *pCursor, 
+  int idxNum, const char *idxStr,
+  int argc, sqlite3_value **argv
 ){
-  int rc = SQLITE_OK;
-  SessionBuffer buf2 = {0,0,0}; /* Buffer to accumulate new.* record in */
-  int bNoop = 1;                /* Set to zero if any values are modified */
-  int nRewind = pBuf->nBuf;     /* Set to zero if any values are modified */
-  int i;                        /* Used to iterate through columns */
-  u8 *pCsr = p->aRecord;        /* Used to iterate through old.* values */
-
-  sessionAppendByte(pBuf, SQLITE_UPDATE, &rc);
-  sessionAppendByte(pBuf, p->bIndirect, &rc);
-  for(i=0; i<sqlite3_column_count(pStmt); i++){
-    int bChanged = 0;
-    int nAdvance;
-    int eType = *pCsr;
-    switch( eType ){
-      case SQLITE_NULL:
-        nAdvance = 1;
-        if( sqlite3_column_type(pStmt, i)!=SQLITE_NULL ){
-          bChanged = 1;
-        }
-        break;
-
-      case SQLITE_FLOAT:
-      case SQLITE_INTEGER: {
-        nAdvance = 9;
-        if( eType==sqlite3_column_type(pStmt, i) ){
-          sqlite3_int64 iVal = sessionGetI64(&pCsr[1]);
-          if( eType==SQLITE_INTEGER ){
-            if( iVal==sqlite3_column_int64(pStmt, i) ) break;
-          }else{
-            double dVal;
-            memcpy(&dVal, &iVal, 8);
-            if( dVal==sqlite3_column_double(pStmt, i) ) break;
-          }
-        }
-        bChanged = 1;
-        break;
-      }
-
-      default: {
-        int n;
-        int nHdr = 1 + sessionVarintGet(&pCsr[1], &n);
-        assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
-        nAdvance = nHdr + n;
-        if( eType==sqlite3_column_type(pStmt, i) 
-         && n==sqlite3_column_bytes(pStmt, i) 
-         && (n==0 || 0==memcmp(&pCsr[nHdr], sqlite3_column_blob(pStmt, i), n))
-        ){
-          break;
-        }
-        bChanged = 1;
-      }
-    }
-
-    /* If at least one field has been modified, this is not a no-op. */
-    if( bChanged ) bNoop = 0;
+  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+  DbpageTable *pTab = (DbpageTable *)pCursor->pVtab;
+  int rc;
+  sqlite3 *db = pTab->db;
+  Btree *pBt;
 
-    /* Add a field to the old.* record. This is omitted if this modules is
-    ** currently generating a patchset. */
-    if( bPatchset==0 ){
-      if( bChanged || abPK[i] ){
-        sessionAppendBlob(pBuf, pCsr, nAdvance, &rc);
-      }else{
-        sessionAppendByte(pBuf, 0, &rc);
-      }
-    }
+  /* Default setting is no rows of result */
+  pCsr->pgno = 1; 
+  pCsr->mxPgno = 0;
 
-    /* Add a field to the new.* record. Or the only record if currently
-    ** generating a patchset.  */
-    if( bChanged || (bPatchset && abPK[i]) ){
-      sessionAppendCol(&buf2, pStmt, i, &rc);
+  if( idxNum & 2 ){
+    const char *zSchema;
+    assert( argc>=1 );
+    zSchema = (const char*)sqlite3_value_text(argv[0]);
+    pCsr->iDb = sqlite3FindDbName(db, zSchema);
+    if( pCsr->iDb<0 ) return SQLITE_OK;
+  }else{
+    pCsr->iDb = 0;
+  }
+  pBt = db->aDb[pCsr->iDb].pBt;
+  if( pBt==0 ) return SQLITE_OK;
+  pCsr->pPager = sqlite3BtreePager(pBt);
+  pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
+  pCsr->mxPgno = sqlite3BtreeLastPage(pBt);
+  if( idxNum & 1 ){
+    assert( argc>(idxNum>>1) );
+    pCsr->pgno = sqlite3_value_int(argv[idxNum>>1]);
+    if( pCsr->pgno<1 || pCsr->pgno>pCsr->mxPgno ){
+      pCsr->pgno = 1;
+      pCsr->mxPgno = 0;
     }else{
-      sessionAppendByte(&buf2, 0, &rc);
+      pCsr->mxPgno = pCsr->pgno;
     }
-
-    pCsr += nAdvance;
-  }
-
-  if( bNoop ){
-    pBuf->nBuf = nRewind;
   }else{
-    sessionAppendBlob(pBuf, buf2.aBuf, buf2.nBuf, &rc);
+    assert( pCsr->pgno==1 );
   }
-  sqlite3_free(buf2.aBuf);
-
+  if( pCsr->pPage1 ) sqlite3PagerUnrefPageOne(pCsr->pPage1);
+  rc = sqlite3PagerGet(pCsr->pPager, 1, &pCsr->pPage1, 0);
   return rc;
 }
 
-/*
-** Append a DELETE change to the buffer passed as the first argument. Use
-** the changeset format if argument bPatchset is zero, or the patchset
-** format otherwise.
-*/
-static int sessionAppendDelete(
-  SessionBuffer *pBuf,            /* Buffer to append to */
-  int bPatchset,                  /* True for "patchset", 0 for "changeset" */
-  SessionChange *p,               /* Object containing old values */
-  int nCol,                       /* Number of columns in table */
-  u8 *abPK                        /* Boolean array - true for PK columns */
+static int dbpageColumn(
+  sqlite3_vtab_cursor *pCursor, 
+  sqlite3_context *ctx, 
+  int i
 ){
+  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
   int rc = SQLITE_OK;
-
-  sessionAppendByte(pBuf, SQLITE_DELETE, &rc);
-  sessionAppendByte(pBuf, p->bIndirect, &rc);
-
-  if( bPatchset==0 ){
-    sessionAppendBlob(pBuf, p->aRecord, p->nRecord, &rc);
-  }else{
-    int i;
-    u8 *a = p->aRecord;
-    for(i=0; i<nCol; i++){
-      u8 *pStart = a;
-      int eType = *a++;
-
-      switch( eType ){
-        case 0:
-        case SQLITE_NULL:
-          assert( abPK[i]==0 );
-          break;
-
-        case SQLITE_FLOAT:
-        case SQLITE_INTEGER:
-          a += 8;
-          break;
-
-        default: {
-          int n;
-          a += sessionVarintGet(a, &n);
-          a += n;
-          break;
-        }
-      }
-      if( abPK[i] ){
-        sessionAppendBlob(pBuf, pStart, (int)(a-pStart), &rc);
+  switch( i ){
+    case 0: {           /* pgno */
+      sqlite3_result_int(ctx, pCsr->pgno);
+      break;
+    }
+    case 1: {           /* data */
+      DbPage *pDbPage = 0;
+      rc = sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
+      if( rc==SQLITE_OK ){
+        sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pCsr->szPage,
+                            SQLITE_TRANSIENT);
       }
+      sqlite3PagerUnref(pDbPage);
+      break;
+    }
+    default: {          /* schema */
+      sqlite3 *db = sqlite3_context_db_handle(ctx);
+      sqlite3_result_text(ctx, db->aDb[pCsr->iDb].zDbSName, -1, SQLITE_STATIC);
+      break;
     }
-    assert( (a - p->aRecord)==p->nRecord );
   }
+  return SQLITE_OK;
+}
 
-  return rc;
+static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
+  DbpageCursor *pCsr = (DbpageCursor *)pCursor;
+  *pRowid = pCsr->pgno;
+  return SQLITE_OK;
 }
 
-/*
-** Formulate and prepare a SELECT statement to retrieve a row from table
-** zTab in database zDb based on its primary key. i.e.
-**
-**   SELECT * FROM zDb.zTab WHERE pk1 = ? AND pk2 = ? AND ...
-*/
-static int sessionSelectStmt(
-  sqlite3 *db,                    /* Database handle */
-  const char *zDb,                /* Database name */
-  const char *zTab,               /* Table name */
-  int nCol,                       /* Number of columns in table */
-  const char **azCol,             /* Names of table columns */
-  u8 *abPK,                       /* PRIMARY KEY  array */
-  sqlite3_stmt **ppStmt           /* OUT: Prepared SELECT statement */
+static int dbpageUpdate(
+  sqlite3_vtab *pVtab,
+  int argc,
+  sqlite3_value **argv,
+  sqlite_int64 *pRowid
 ){
+  DbpageTable *pTab = (DbpageTable *)pVtab;
+  Pgno pgno;
+  DbPage *pDbPage = 0;
   int rc = SQLITE_OK;
-  char *zSql = 0;
-  int nSql = -1;
-
-  if( 0==sqlite3_stricmp("sqlite_stat1", zTab) ){
-    zSql = sqlite3_mprintf(
-        "SELECT tbl, ?2, stat FROM %Q.sqlite_stat1 WHERE tbl IS ?1 AND "
-        "idx IS (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", zDb
-    );
-    if( zSql==0 ) rc = SQLITE_NOMEM;
-  }else{
-    int i;
-    const char *zSep = "";
-    SessionBuffer buf = {0, 0, 0};
+  char *zErr = 0;
+  const char *zSchema;
+  int iDb;
+  Btree *pBt;
+  Pager *pPager;
+  int szPage;
 
-    sessionAppendStr(&buf, "SELECT * FROM ", &rc);
-    sessionAppendIdent(&buf, zDb, &rc);
-    sessionAppendStr(&buf, ".", &rc);
-    sessionAppendIdent(&buf, zTab, &rc);
-    sessionAppendStr(&buf, " WHERE ", &rc);
-    for(i=0; i<nCol; i++){
-      if( abPK[i] ){
-        sessionAppendStr(&buf, zSep, &rc);
-        sessionAppendIdent(&buf, azCol[i], &rc);
-        sessionAppendStr(&buf, " IS ?", &rc);
-        sessionAppendInteger(&buf, i+1, &rc);
-        zSep = " AND ";
-      }
-    }
-    zSql = (char*)buf.aBuf;
-    nSql = buf.nBuf;
+  if( argc==1 ){
+    zErr = "cannot delete";
+    goto update_fail;
   }
-
+  pgno = sqlite3_value_int(argv[0]);
+  if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){
+    zErr = "cannot insert";
+    goto update_fail;
+  }
+  zSchema = (const char*)sqlite3_value_text(argv[4]);
+  iDb = zSchema ? sqlite3FindDbName(pTab->db, zSchema) : -1;
+  if( iDb<0 ){
+    zErr = "no such schema";
+    goto update_fail;
+  }
+  pBt = pTab->db->aDb[iDb].pBt;
+  if( pgno<1 || pBt==0 || pgno>(int)sqlite3BtreeLastPage(pBt) ){
+    zErr = "bad page number";
+    goto update_fail;
+  }
+  szPage = sqlite3BtreeGetPageSize(pBt);
+  if( sqlite3_value_type(argv[3])!=SQLITE_BLOB 
+   || sqlite3_value_bytes(argv[3])!=szPage
+  ){
+    zErr = "bad page value";
+    goto update_fail;
+  }
+  pPager = sqlite3BtreePager(pBt);
+  rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0);
   if( rc==SQLITE_OK ){
-    rc = sqlite3_prepare_v2(db, zSql, nSql, ppStmt, 0);
+    rc = sqlite3PagerWrite(pDbPage);
+    if( rc==SQLITE_OK ){
+      memcpy(sqlite3PagerGetData(pDbPage),
+             sqlite3_value_blob(argv[3]),
+             szPage);
+    }
   }
-  sqlite3_free(zSql);
+  sqlite3PagerUnref(pDbPage);
   return rc;
+
+update_fail:
+  sqlite3_free(pVtab->zErrMsg);
+  pVtab->zErrMsg = sqlite3_mprintf("%s", zErr);
+  return SQLITE_ERROR;
 }
 
-/*
-** Bind the PRIMARY KEY values from the change passed in argument pChange
-** to the SELECT statement passed as the first argument. The SELECT statement
-** is as prepared by function sessionSelectStmt().
-**
-** Return SQLITE_OK if all PK values are successfully bound, or an SQLite
-** error code (e.g. SQLITE_NOMEM) otherwise.
+/* Since we do not know in advance which database files will be
+** written by the sqlite_dbpage virtual table, start a write transaction
+** on them all.
 */
-static int sessionSelectBind(
-  sqlite3_stmt *pSelect,          /* SELECT from sessionSelectStmt() */
-  int nCol,                       /* Number of columns in table */
-  u8 *abPK,                       /* PRIMARY KEY array */
-  SessionChange *pChange          /* Change structure */
-){
+static int dbpageBegin(sqlite3_vtab *pVtab){
+  DbpageTable *pTab = (DbpageTable *)pVtab;
+  sqlite3 *db = pTab->db;
   int i;
-  int rc = SQLITE_OK;
-  u8 *a = pChange->aRecord;
-
-  for(i=0; i<nCol && rc==SQLITE_OK; i++){
-    int eType = *a++;
-
-    switch( eType ){
-      case 0:
-      case SQLITE_NULL:
-        assert( abPK[i]==0 );
-        break;
-
-      case SQLITE_INTEGER: {
-        if( abPK[i] ){
-          i64 iVal = sessionGetI64(a);
-          rc = sqlite3_bind_int64(pSelect, i+1, iVal);
-        }
-        a += 8;
-        break;
-      }
-
-      case SQLITE_FLOAT: {
-        if( abPK[i] ){
-          double rVal;
-          i64 iVal = sessionGetI64(a);
-          memcpy(&rVal, &iVal, 8);
-          rc = sqlite3_bind_double(pSelect, i+1, rVal);
-        }
-        a += 8;
-        break;
-      }
-
-      case SQLITE_TEXT: {
-        int n;
-        a += sessionVarintGet(a, &n);
-        if( abPK[i] ){
-          rc = sqlite3_bind_text(pSelect, i+1, (char *)a, n, SQLITE_TRANSIENT);
-        }
-        a += n;
-        break;
-      }
-
-      default: {
-        int n;
-        assert( eType==SQLITE_BLOB );
-        a += sessionVarintGet(a, &n);
-        if( abPK[i] ){
-          rc = sqlite3_bind_blob(pSelect, i+1, a, n, SQLITE_TRANSIENT);
-        }
-        a += n;
-        break;
-      }
-    }
+  for(i=0; i<db->nDb; i++){
+    Btree *pBt = db->aDb[i].pBt;
+    if( pBt ) sqlite3BtreeBeginTrans(pBt, 1, 0);
   }
-
-  return rc;
+  return SQLITE_OK;
 }
 
-/*
-** This function is a no-op if *pRc is set to other than SQLITE_OK when it
-** is called. Otherwise, append a serialized table header (part of the binary 
-** changeset format) to buffer *pBuf. If an error occurs, set *pRc to an
-** SQLite error code before returning.
-*/
-static void sessionAppendTableHdr(
-  SessionBuffer *pBuf,            /* Append header to this buffer */
-  int bPatchset,                  /* Use the patchset format if true */
-  SessionTable *pTab,             /* Table object to append header for */
-  int *pRc                        /* IN/OUT: Error code */
-){
-  /* Write a table header */
-  sessionAppendByte(pBuf, (bPatchset ? 'P' : 'T'), pRc);
-  sessionAppendVarint(pBuf, pTab->nCol, pRc);
-  sessionAppendBlob(pBuf, pTab->abPK, pTab->nCol, pRc);
-  sessionAppendBlob(pBuf, (u8 *)pTab->zName, (int)strlen(pTab->zName)+1, pRc);
-}
 
 /*
-** Generate either a changeset (if argument bPatchset is zero) or a patchset
-** (if it is non-zero) based on the current contents of the session object
-** passed as the first argument.
-**
-** If no error occurs, SQLITE_OK is returned and the new changeset/patchset
-** stored in output variables *pnChangeset and *ppChangeset. Or, if an error
-** occurs, an SQLite error code is returned and both output variables set 
-** to 0.
+** Invoke this routine to register the "dbpage" virtual table module
 */
-static int sessionGenerateChangeset(
-  sqlite3_session *pSession,      /* Session object */
-  int bPatchset,                  /* True for patchset, false for changeset */
-  int (*xOutput)(void *pOut, const void *pData, int nData),
-  void *pOut,                     /* First argument for xOutput */
-  int *pnChangeset,               /* OUT: Size of buffer at *ppChangeset */
-  void **ppChangeset              /* OUT: Buffer containing changeset */
-){
-  sqlite3 *db = pSession->db;     /* Source database handle */
-  SessionTable *pTab;             /* Used to iterate through attached tables */
-  SessionBuffer buf = {0,0,0};    /* Buffer in which to accumlate changeset */
-  int rc;                         /* Return code */
-
-  assert( xOutput==0 || (pnChangeset==0 && ppChangeset==0 ) );
-
-  /* Zero the output variables in case an error occurs. If this session
-  ** object is already in the error state (sqlite3_session.rc != SQLITE_OK),
-  ** this call will be a no-op.  */
-  if( xOutput==0 ){
-    *pnChangeset = 0;
-    *ppChangeset = 0;
-  }
-
-  if( pSession->rc ) return pSession->rc;
-  rc = sqlite3_exec(pSession->db, "SAVEPOINT changeset", 0, 0, 0);
-  if( rc!=SQLITE_OK ) return rc;
-
-  sqlite3_mutex_enter(sqlite3_db_mutex(db));
-
-  for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
-    if( pTab->nEntry ){
-      const char *zName = pTab->zName;
-      int nCol;                   /* Number of columns in table */
-      u8 *abPK;                   /* Primary key array */
-      const char **azCol = 0;     /* Table columns */
-      int i;                      /* Used to iterate through hash buckets */
-      sqlite3_stmt *pSel = 0;     /* SELECT statement to query table pTab */
-      int nRewind = buf.nBuf;     /* Initial size of write buffer */
-      int nNoop;                  /* Size of buffer after writing tbl header */
-
-      /* Check the table schema is still Ok. */
-      rc = sessionTableInfo(db, pSession->zDb, zName, &nCol, 0, &azCol, &abPK);
-      if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){
-        rc = SQLITE_SCHEMA;
-      }
-
-      /* Write a table header */
-      sessionAppendTableHdr(&buf, bPatchset, pTab, &rc);
-
-      /* Build and compile a statement to execute: */
-      if( rc==SQLITE_OK ){
-        rc = sessionSelectStmt(
-            db, pSession->zDb, zName, nCol, azCol, abPK, &pSel);
-      }
-
-      nNoop = buf.nBuf;
-      for(i=0; i<pTab->nChange && rc==SQLITE_OK; i++){
-        SessionChange *p;         /* Used to iterate through changes */
-
-        for(p=pTab->apChange[i]; rc==SQLITE_OK && p; p=p->pNext){
-          rc = sessionSelectBind(pSel, nCol, abPK, p);
-          if( rc!=SQLITE_OK ) continue;
-          if( sqlite3_step(pSel)==SQLITE_ROW ){
-            if( p->op==SQLITE_INSERT ){
-              int iCol;
-              sessionAppendByte(&buf, SQLITE_INSERT, &rc);
-              sessionAppendByte(&buf, p->bIndirect, &rc);
-              for(iCol=0; iCol<nCol; iCol++){
-                sessionAppendCol(&buf, pSel, iCol, &rc);
-              }
-            }else{
-              rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, abPK);
-            }
-          }else if( p->op!=SQLITE_INSERT ){
-            rc = sessionAppendDelete(&buf, bPatchset, p, nCol, abPK);
-          }
-          if( rc==SQLITE_OK ){
-            rc = sqlite3_reset(pSel);
-          }
-
-          /* If the buffer is now larger than SESSIONS_STRM_CHUNK_SIZE, pass
-          ** its contents to the xOutput() callback. */
-          if( xOutput 
-           && rc==SQLITE_OK 
-           && buf.nBuf>nNoop 
-           && buf.nBuf>SESSIONS_STRM_CHUNK_SIZE 
-          ){
-            rc = xOutput(pOut, (void*)buf.aBuf, buf.nBuf);
-            nNoop = -1;
-            buf.nBuf = 0;
-          }
+SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){
+  static sqlite3_module dbpage_module = {
+    0,                            /* iVersion */
+    dbpageConnect,                /* xCreate */
+    dbpageConnect,                /* xConnect */
+    dbpageBestIndex,              /* xBestIndex */
+    dbpageDisconnect,             /* xDisconnect */
+    dbpageDisconnect,             /* xDestroy */
+    dbpageOpen,                   /* xOpen - open a cursor */
+    dbpageClose,                  /* xClose - close a cursor */
+    dbpageFilter,                 /* xFilter - configure scan constraints */
+    dbpageNext,                   /* xNext - advance a cursor */
+    dbpageEof,                    /* xEof - check for end of scan */
+    dbpageColumn,                 /* xColumn - read data */
+    dbpageRowid,                  /* xRowid - read data */
+    dbpageUpdate,                 /* xUpdate */
+    dbpageBegin,                  /* xBegin */
+    0,                            /* xSync */
+    0,                            /* xCommit */
+    0,                            /* xRollback */
+    0,                            /* xFindMethod */
+    0,                            /* xRename */
+    0,                            /* xSavepoint */
+    0,                            /* xRelease */
+    0,                            /* xRollbackTo */
+  };
+  return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
+}
+#elif defined(SQLITE_ENABLE_DBPAGE_VTAB)
+SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){ return SQLITE_OK; }
+#endif /* SQLITE_ENABLE_DBSTAT_VTAB */
 
-        }
-      }
+/************** End of dbpage.c **********************************************/
+/************** Begin file sqlite3session.c **********************************/
 
-      sqlite3_finalize(pSel);
-      if( buf.nBuf==nNoop ){
-        buf.nBuf = nRewind;
-      }
-      sqlite3_free((char*)azCol);  /* cast works around VC++ bug */
-    }
-  }
+#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
+/* #include "sqlite3session.h" */
+/* #include <assert.h> */
+/* #include <string.h> */
 
-  if( rc==SQLITE_OK ){
-    if( xOutput==0 ){
-      *pnChangeset = buf.nBuf;
-      *ppChangeset = buf.aBuf;
-      buf.aBuf = 0;
-    }else if( buf.nBuf>0 ){
-      rc = xOutput(pOut, (void*)buf.aBuf, buf.nBuf);
-    }
-  }
+#ifndef SQLITE_AMALGAMATION
+/* # include "sqliteInt.h" */
+/* # include "vdbeInt.h" */
+#endif
 
-  sqlite3_free(buf.aBuf);
-  sqlite3_exec(db, "RELEASE changeset", 0, 0, 0);
-  sqlite3_mutex_leave(sqlite3_db_mutex(db));
-  return rc;
-}
+typedef struct SessionTable SessionTable;
+typedef struct SessionChange SessionChange;
+typedef struct SessionBuffer SessionBuffer;
+typedef struct SessionInput SessionInput;
 
 /*
-** Obtain a changeset object containing all changes recorded by the 
-** session object passed as the first argument.
-**
-** It is the responsibility of the caller to eventually free the buffer 
-** using sqlite3_free().
+** Minimum chunk size used by streaming versions of functions.
 */
-SQLITE_API int sqlite3session_changeset(
-  sqlite3_session *pSession,      /* Session object */
-  int *pnChangeset,               /* OUT: Size of buffer at *ppChangeset */
-  void **ppChangeset              /* OUT: Buffer containing changeset */
-){
-  return sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset, ppChangeset);
-}
+#ifndef SESSIONS_STRM_CHUNK_SIZE
+# ifdef SQLITE_TEST
+#   define SESSIONS_STRM_CHUNK_SIZE 64
+# else
+#   define SESSIONS_STRM_CHUNK_SIZE 1024
+# endif
+#endif
 
-/*
-** Streaming version of sqlite3session_changeset().
-*/
-SQLITE_API int sqlite3session_changeset_strm(
-  sqlite3_session *pSession,
-  int (*xOutput)(void *pOut, const void *pData, int nData),
-  void *pOut
-){
-  return sessionGenerateChangeset(pSession, 0, xOutput, pOut, 0, 0);
-}
+typedef struct SessionHook SessionHook;
+struct SessionHook {
+  void *pCtx;
+  int (*xOld)(void*,int,sqlite3_value**);
+  int (*xNew)(void*,int,sqlite3_value**);
+  int (*xCount)(void*);
+  int (*xDepth)(void*);
+};
 
 /*
-** Streaming version of sqlite3session_patchset().
+** Session handle structure.
 */
-SQLITE_API int sqlite3session_patchset_strm(
-  sqlite3_session *pSession,
-  int (*xOutput)(void *pOut, const void *pData, int nData),
-  void *pOut
-){
-  return sessionGenerateChangeset(pSession, 1, xOutput, pOut, 0, 0);
-}
+struct sqlite3_session {
+  sqlite3 *db;                    /* Database handle session is attached to */
+  char *zDb;                      /* Name of database session is attached to */
+  int bEnable;                    /* True if currently recording */
+  int bIndirect;                  /* True if all changes are indirect */
+  int bAutoAttach;                /* True to auto-attach tables */
+  int rc;                         /* Non-zero if an error has occurred */
+  void *pFilterCtx;               /* First argument to pass to xTableFilter */
+  int (*xTableFilter)(void *pCtx, const char *zTab);
+  sqlite3_value *pZeroBlob;       /* Value containing X'' */
+  sqlite3_session *pNext;         /* Next session object on same db. */
+  SessionTable *pTable;           /* List of attached tables */
+  SessionHook hook;               /* APIs to grab new and old data with */
+};
 
 /*
-** Obtain a patchset object containing all changes recorded by the 
-** session object passed as the first argument.
-**
-** It is the responsibility of the caller to eventually free the buffer 
-** using sqlite3_free().
+** Instances of this structure are used to build strings or binary records.
 */
-SQLITE_API int sqlite3session_patchset(
-  sqlite3_session *pSession,      /* Session object */
-  int *pnPatchset,                /* OUT: Size of buffer at *ppChangeset */
-  void **ppPatchset               /* OUT: Buffer containing changeset */
-){
-  return sessionGenerateChangeset(pSession, 1, 0, 0, pnPatchset, ppPatchset);
-}
+struct SessionBuffer {
+  u8 *aBuf;                       /* Pointer to changeset buffer */
+  int nBuf;                       /* Size of buffer aBuf */
+  int nAlloc;                     /* Size of allocation containing aBuf */
+};
 
 /*
-** Enable or disable the session object passed as the first argument.
+** An object of this type is used internally as an abstraction for 
+** input data. Input data may be supplied either as a single large buffer
+** (e.g. sqlite3changeset_start()) or using a stream function (e.g.
+**  sqlite3changeset_start_strm()).
 */
-SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable){
-  int ret;
-  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
-  if( bEnable>=0 ){
-    pSession->bEnable = bEnable;
-  }
-  ret = pSession->bEnable;
-  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
-  return ret;
-}
+struct SessionInput {
+  int bNoDiscard;                 /* If true, do not discard in InputBuffer() */
+  int iCurrent;                   /* Offset in aData[] of current change */
+  int iNext;                      /* Offset in aData[] of next change */
+  u8 *aData;                      /* Pointer to buffer containing changeset */
+  int nData;                      /* Number of bytes in aData */
 
-/*
-** Enable or disable the session object passed as the first argument.
-*/
-SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect){
-  int ret;
-  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
-  if( bIndirect>=0 ){
-    pSession->bIndirect = bIndirect;
-  }
-  ret = pSession->bIndirect;
-  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
-  return ret;
-}
+  SessionBuffer buf;              /* Current read buffer */
+  int (*xInput)(void*, void*, int*);        /* Input stream call (or NULL) */
+  void *pIn;                                /* First argument to xInput */
+  int bEof;                       /* Set to true after xInput finished */
+};
 
 /*
-** Return true if there have been no changes to monitored tables recorded
-** by the session object passed as the only argument.
+** Structure for changeset iterators.
 */
-SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession){
-  int ret = 0;
-  SessionTable *pTab;
-
-  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
-  for(pTab=pSession->pTable; pTab && ret==0; pTab=pTab->pNext){
-    ret = (pTab->nEntry>0);
-  }
-  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
-
-  return (ret==0);
-}
+struct sqlite3_changeset_iter {
+  SessionInput in;                /* Input buffer or stream */
+  SessionBuffer tblhdr;           /* Buffer to hold apValue/zTab/abPK/ */
+  int bPatchset;                  /* True if this is a patchset */
+  int rc;                         /* Iterator error code */
+  sqlite3_stmt *pConflict;        /* Points to conflicting row, if any */
+  char *zTab;                     /* Current table */
+  int nCol;                       /* Number of columns in zTab */
+  int op;                         /* Current operation */
+  int bIndirect;                  /* True if current change was indirect */
+  u8 *abPK;                       /* Primary key array */
+  sqlite3_value **apValue;        /* old.* and new.* values */
+};
 
 /*
-** Do the work for either sqlite3changeset_start() or start_strm().
+** Each session object maintains a set of the following structures, one
+** for each table the session object is monitoring. The structures are
+** stored in a linked list starting at sqlite3_session.pTable.
+**
+** The keys of the SessionTable.aChange[] hash table are all rows that have
+** been modified in any way since the session object was attached to the
+** table.
+**
+** The data associated with each hash-table entry is a structure containing
+** a subset of the initial values that the modified row contained at the
+** start of the session. Or no initial values if the row was inserted.
 */
-static int sessionChangesetStart(
-  sqlite3_changeset_iter **pp,    /* OUT: Changeset iterator handle */
-  int (*xInput)(void *pIn, void *pData, int *pnData),
-  void *pIn,
-  int nChangeset,                 /* Size of buffer pChangeset in bytes */
-  void *pChangeset                /* Pointer to buffer containing changeset */
-){
-  sqlite3_changeset_iter *pRet;   /* Iterator to return */
-  int nByte;                      /* Number of bytes to allocate for iterator */
-
-  assert( xInput==0 || (pChangeset==0 && nChangeset==0) );
-
-  /* Zero the output variable in case an error occurs. */
-  *pp = 0;
-
-  /* Allocate and initialize the iterator structure. */
-  nByte = sizeof(sqlite3_changeset_iter);
-  pRet = (sqlite3_changeset_iter *)sqlite3_malloc(nByte);
-  if( !pRet ) return SQLITE_NOMEM;
-  memset(pRet, 0, sizeof(sqlite3_changeset_iter));
-  pRet->in.aData = (u8 *)pChangeset;
-  pRet->in.nData = nChangeset;
-  pRet->in.xInput = xInput;
-  pRet->in.pIn = pIn;
-  pRet->in.bEof = (xInput ? 0 : 1);
+struct SessionTable {
+  SessionTable *pNext;
+  char *zName;                    /* Local name of table */
+  int nCol;                       /* Number of columns in table zName */
+  int bStat1;                     /* True if this is sqlite_stat1 */
+  const char **azCol;             /* Column names */
+  u8 *abPK;                       /* Array of primary key flags */
+  int nEntry;                     /* Total number of entries in hash table */
+  int nChange;                    /* Size of apChange[] array */
+  SessionChange **apChange;       /* Hash table buckets */
+};
 
-  /* Populate the output variable and return success. */
-  *pp = pRet;
-  return SQLITE_OK;
-}
+/* 
+** RECORD FORMAT:
+**
+** The following record format is similar to (but not compatible with) that 
+** used in SQLite database files. This format is used as part of the 
+** change-set binary format, and so must be architecture independent.
+**
+** Unlike the SQLite database record format, each field is self-contained -
+** there is no separation of header and data. Each field begins with a
+** single byte describing its type, as follows:
+**
+**       0x00: Undefined value.
+**       0x01: Integer value.
+**       0x02: Real value.
+**       0x03: Text value.
+**       0x04: Blob value.
+**       0x05: SQL NULL value.
+**
+** Note that the above match the definitions of SQLITE_INTEGER, SQLITE_TEXT
+** and so on in sqlite3.h. For undefined and NULL values, the field consists
+** only of the single type byte. For other types of values, the type byte
+** is followed by:
+**
+**   Text values:
+**     A varint containing the number of bytes in the value (encoded using
+**     UTF-8). Followed by a buffer containing the UTF-8 representation
+**     of the text value. There is no nul terminator.
+**
+**   Blob values:
+**     A varint containing the number of bytes in the value, followed by
+**     a buffer containing the value itself.
+**
+**   Integer values:
+**     An 8-byte big-endian integer value.
+**
+**   Real values:
+**     An 8-byte big-endian IEEE 754-2008 real value.
+**
+** Varint values are encoded in the same way as varints in the SQLite 
+** record format.
+**
+** CHANGESET FORMAT:
+**
+** A changeset is a collection of DELETE, UPDATE and INSERT operations on
+** one or more tables. Operations on a single table are grouped together,
+** but may occur in any order (i.e. deletes, updates and inserts are all
+** mixed together).
+**
+** Each group of changes begins with a table header:
+**
+**   1 byte: Constant 0x54 (capital 'T')
+**   Varint: Number of columns in the table.
+**   nCol bytes: 0x01 for PK columns, 0x00 otherwise.
+**   N bytes: Unqualified table name (encoded using UTF-8). Nul-terminated.
+**
+** Followed by one or more changes to the table.
+**
+**   1 byte: Either SQLITE_INSERT (0x12), UPDATE (0x17) or DELETE (0x09).
+**   1 byte: The "indirect-change" flag.
+**   old.* record: (delete and update only)
+**   new.* record: (insert and update only)
+**
+** The "old.*" and "new.*" records, if present, are N field records in the
+** format described above under "RECORD FORMAT", where N is the number of
+** columns in the table. The i'th field of each record is associated with
+** the i'th column of the table, counting from left to right in the order
+** in which columns were declared in the CREATE TABLE statement.
+**
+** The new.* record that is part of each INSERT change contains the values
+** that make up the new row. Similarly, the old.* record that is part of each
+** DELETE change contains the values that made up the row that was deleted 
+** from the database. In the changeset format, the records that are part
+** of INSERT or DELETE changes never contain any undefined (type byte 0x00)
+** fields.
+**
+** Within the old.* record associated with an UPDATE change, all fields
+** associated with table columns that are not PRIMARY KEY columns and are
+** not modified by the UPDATE change are set to "undefined". Other fields
+** are set to the values that made up the row before the UPDATE that the
+** change records took place. Within the new.* record, fields associated 
+** with table columns modified by the UPDATE change contain the new 
+** values. Fields associated with table columns that are not modified
+** are set to "undefined".
+**
+** PATCHSET FORMAT:
+**
+** A patchset is also a collection of changes. It is similar to a changeset,
+** but leaves undefined those fields that are not useful if no conflict
+** resolution is required when applying the changeset.
+**
+** Each group of changes begins with a table header:
+**
+**   1 byte: Constant 0x50 (capital 'P')
+**   Varint: Number of columns in the table.
+**   nCol bytes: 0x01 for PK columns, 0x00 otherwise.
+**   N bytes: Unqualified table name (encoded using UTF-8). Nul-terminated.
+**
+** Followed by one or more changes to the table.
+**
+**   1 byte: Either SQLITE_INSERT (0x12), UPDATE (0x17) or DELETE (0x09).
+**   1 byte: The "indirect-change" flag.
+**   single record: (PK fields for DELETE, PK and modified fields for UPDATE,
+**                   full record for INSERT).
+**
+** As in the changeset format, each field of the single record that is part
+** of a patchset change is associated with the correspondingly positioned
+** table column, counting from left to right within the CREATE TABLE 
+** statement.
+**
+** For a DELETE change, all fields within the record except those associated
+** with PRIMARY KEY columns are omitted. The PRIMARY KEY fields contain the
+** values identifying the row to delete.
+**
+** For an UPDATE change, all fields except those associated with PRIMARY KEY
+** columns and columns that are modified by the UPDATE are set to "undefined".
+** PRIMARY KEY fields contain the values identifying the table row to update,
+** and fields associated with modified columns contain the new column values.
+**
+** The records associated with INSERT changes are in the same format as for
+** changesets. It is not possible for a record associated with an INSERT
+** change to contain a field set to "undefined".
+*/
 
 /*
-** Create an iterator used to iterate through the contents of a changeset.
+** For each row modified during a session, there exists a single instance of
+** this structure stored in a SessionTable.aChange[] hash table.
 */
-SQLITE_API int sqlite3changeset_start(
-  sqlite3_changeset_iter **pp,    /* OUT: Changeset iterator handle */
-  int nChangeset,                 /* Size of buffer pChangeset in bytes */
-  void *pChangeset                /* Pointer to buffer containing changeset */
-){
-  return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset);
-}
+struct SessionChange {
+  int op;                         /* One of UPDATE, DELETE, INSERT */
+  int bIndirect;                  /* True if this change is "indirect" */
+  int nRecord;                    /* Number of bytes in buffer aRecord[] */
+  u8 *aRecord;                    /* Buffer containing old.* record */
+  SessionChange *pNext;           /* For hash-table collisions */
+};
 
 /*
-** Streaming version of sqlite3changeset_start().
+** Write a varint with value iVal into the buffer at aBuf. Return the 
+** number of bytes written.
 */
-SQLITE_API int sqlite3changeset_start_strm(
-  sqlite3_changeset_iter **pp,    /* OUT: Changeset iterator handle */
-  int (*xInput)(void *pIn, void *pData, int *pnData),
-  void *pIn
-){
-  return sessionChangesetStart(pp, xInput, pIn, 0, 0);
+static int sessionVarintPut(u8 *aBuf, int iVal){
+  return putVarint32(aBuf, iVal);
 }
 
 /*
-** If the SessionInput object passed as the only argument is a streaming
-** object and the buffer is full, discard some data to free up space.
+** Return the number of bytes required to store value iVal as a varint.
 */
-static void sessionDiscardData(SessionInput *pIn){
-  if( pIn->xInput && pIn->iNext>=SESSIONS_STRM_CHUNK_SIZE ){
-    int nMove = pIn->buf.nBuf - pIn->iNext;
-    assert( nMove>=0 );
-    if( nMove>0 ){
-      memmove(pIn->buf.aBuf, &pIn->buf.aBuf[pIn->iNext], nMove);
-    }
-    pIn->buf.nBuf -= pIn->iNext;
-    pIn->iNext = 0;
-    pIn->nData = pIn->buf.nBuf;
-  }
+static int sessionVarintLen(int iVal){
+  return sqlite3VarintLen(iVal);
 }
 
 /*
-** Ensure that there are at least nByte bytes available in the buffer. Or,
-** if there are not nByte bytes remaining in the input, that all available
-** data is in the buffer.
-**
-** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise.
+** Read a varint value from aBuf[] into *piVal. Return the number of 
+** bytes read.
 */
-static int sessionInputBuffer(SessionInput *pIn, int nByte){
-  int rc = SQLITE_OK;
-  if( pIn->xInput ){
-    while( !pIn->bEof && (pIn->iNext+nByte)>=pIn->nData && rc==SQLITE_OK ){
-      int nNew = SESSIONS_STRM_CHUNK_SIZE;
-
-      if( pIn->bNoDiscard==0 ) sessionDiscardData(pIn);
-      if( SQLITE_OK==sessionBufferGrow(&pIn->buf, nNew, &rc) ){
-        rc = pIn->xInput(pIn->pIn, &pIn->buf.aBuf[pIn->buf.nBuf], &nNew);
-        if( nNew==0 ){
-          pIn->bEof = 1;
-        }else{
-          pIn->buf.nBuf += nNew;
-        }
-      }
-
-      pIn->aData = pIn->buf.aBuf;
-      pIn->nData = pIn->buf.nBuf;
-    }
-  }
-  return rc;
+static int sessionVarintGet(u8 *aBuf, int *piVal){
+  return getVarint32(aBuf, *piVal);
 }
 
+/* Load an unaligned and unsigned 32-bit integer */
+#define SESSION_UINT32(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3])
+
 /*
-** When this function is called, *ppRec points to the start of a record
-** that contains nCol values. This function advances the pointer *ppRec
-** until it points to the byte immediately following that record.
+** Read a 64-bit big-endian integer value from buffer aRec[]. Return
+** the value read.
 */
-static void sessionSkipRecord(
-  u8 **ppRec,                     /* IN/OUT: Record pointer */
-  int nCol                        /* Number of values in record */
-){
-  u8 *aRec = *ppRec;
-  int i;
-  for(i=0; i<nCol; i++){
-    int eType = *aRec++;
-    if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
-      int nByte;
-      aRec += sessionVarintGet((u8*)aRec, &nByte);
-      aRec += nByte;
-    }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
-      aRec += 8;
-    }
-  }
-
-  *ppRec = aRec;
+static sqlite3_int64 sessionGetI64(u8 *aRec){
+  u64 x = SESSION_UINT32(aRec);
+  u32 y = SESSION_UINT32(aRec+4);
+  x = (x<<32) + y;
+  return (sqlite3_int64)x;
 }
 
 /*
-** This function sets the value of the sqlite3_value object passed as the
-** first argument to a copy of the string or blob held in the aData[] 
-** buffer. SQLITE_OK is returned if successful, or SQLITE_NOMEM if an OOM
-** error occurs.
+** Write a 64-bit big-endian integer value to the buffer aBuf[].
 */
-static int sessionValueSetStr(
-  sqlite3_value *pVal,            /* Set the value of this object */
-  u8 *aData,                      /* Buffer containing string or blob data */
-  int nData,                      /* Size of buffer aData[] in bytes */
-  u8 enc                          /* String encoding (0 for blobs) */
-){
-  /* In theory this code could just pass SQLITE_TRANSIENT as the final
-  ** argument to sqlite3ValueSetStr() and have the copy created 
-  ** automatically. But doing so makes it difficult to detect any OOM
-  ** error. Hence the code to create the copy externally. */
-  u8 *aCopy = sqlite3_malloc(nData+1);
-  if( aCopy==0 ) return SQLITE_NOMEM;
-  memcpy(aCopy, aData, nData);
-  sqlite3ValueSetStr(pVal, nData, (char*)aCopy, enc, sqlite3_free);
-  return SQLITE_OK;
+static void sessionPutI64(u8 *aBuf, sqlite3_int64 i){
+  aBuf[0] = (i>>56) & 0xFF;
+  aBuf[1] = (i>>48) & 0xFF;
+  aBuf[2] = (i>>40) & 0xFF;
+  aBuf[3] = (i>>32) & 0xFF;
+  aBuf[4] = (i>>24) & 0xFF;
+  aBuf[5] = (i>>16) & 0xFF;
+  aBuf[6] = (i>> 8) & 0xFF;
+  aBuf[7] = (i>> 0) & 0xFF;
 }
 
 /*
-** Deserialize a single record from a buffer in memory. See "RECORD FORMAT"
-** for details.
-**
-** When this function is called, *paChange points to the start of the record
-** to deserialize. Assuming no error occurs, *paChange is set to point to
-** one byte after the end of the same record before this function returns.
-** If the argument abPK is NULL, then the record contains nCol values. Or,
-** if abPK is other than NULL, then the record contains only the PK fields
-** (in other words, it is a patchset DELETE record).
-**
-** If successful, each element of the apOut[] array (allocated by the caller)
-** is set to point to an sqlite3_value object containing the value read
-** from the corresponding position in the record. If that value is not
-** included in the record (i.e. because the record is part of an UPDATE change
-** and the field was not modified), the corresponding element of apOut[] is
-** set to NULL.
+** This function is used to serialize the contents of value pValue (see
+** comment titled "RECORD FORMAT" above).
 **
-** It is the responsibility of the caller to free all sqlite_value structures
-** using sqlite3_free().
+** If it is non-NULL, the serialized form of the value is written to 
+** buffer aBuf. *pnWrite is set to the number of bytes written before
+** returning. Or, if aBuf is NULL, the only thing this function does is
+** set *pnWrite.
 **
-** If an error occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.
-** The apOut[] array may have been partially populated in this case.
+** If no error occurs, SQLITE_OK is returned. Or, if an OOM error occurs
+** within a call to sqlite3_value_text() (may fail if the db is utf-16)) 
+** SQLITE_NOMEM is returned.
 */
-static int sessionReadRecord(
-  SessionInput *pIn,              /* Input data */
-  int nCol,                       /* Number of values in record */
-  u8 *abPK,                       /* Array of primary key flags, or NULL */
-  sqlite3_value **apOut           /* Write values to this array */
+static int sessionSerializeValue(
+  u8 *aBuf,                       /* If non-NULL, write serialized value here */
+  sqlite3_value *pValue,          /* Value to serialize */
+  int *pnWrite                    /* IN/OUT: Increment by bytes written */
 ){
-  int i;                          /* Used to iterate through columns */
-  int rc = SQLITE_OK;
-
-  for(i=0; i<nCol && rc==SQLITE_OK; i++){
-    int eType = 0;                /* Type of value (SQLITE_NULL, TEXT etc.) */
-    if( abPK && abPK[i]==0 ) continue;
-    rc = sessionInputBuffer(pIn, 9);
-    if( rc==SQLITE_OK ){
-      if( pIn->iNext>=pIn->nData ){
-        rc = SQLITE_CORRUPT_BKPT;
-      }else{
-        eType = pIn->aData[pIn->iNext++];
-        assert( apOut[i]==0 );
-        if( eType ){
-          apOut[i] = sqlite3ValueNew(0);
-          if( !apOut[i] ) rc = SQLITE_NOMEM;
-        }
-      }
-    }
+  int nByte;                      /* Size of serialized value in bytes */
 
-    if( rc==SQLITE_OK ){
-      u8 *aVal = &pIn->aData[pIn->iNext];
-      if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
-        int nByte;
-        pIn->iNext += sessionVarintGet(aVal, &nByte);
-        rc = sessionInputBuffer(pIn, nByte);
-        if( rc==SQLITE_OK ){
-          if( nByte<0 || nByte>pIn->nData-pIn->iNext ){
-            rc = SQLITE_CORRUPT_BKPT;
+  if( pValue ){
+    int eType;                    /* Value type (SQLITE_NULL, TEXT etc.) */
+  
+    eType = sqlite3_value_type(pValue);
+    if( aBuf ) aBuf[0] = eType;
+  
+    switch( eType ){
+      case SQLITE_NULL: 
+        nByte = 1;
+        break;
+  
+      case SQLITE_INTEGER: 
+      case SQLITE_FLOAT:
+        if( aBuf ){
+          /* TODO: SQLite does something special to deal with mixed-endian
+          ** floating point values (e.g. ARM7). This code probably should
+          ** too.  */
+          u64 i;
+          if( eType==SQLITE_INTEGER ){
+            i = (u64)sqlite3_value_int64(pValue);
           }else{
-            u8 enc = (eType==SQLITE_TEXT ? SQLITE_UTF8 : 0);
-            rc = sessionValueSetStr(apOut[i],&pIn->aData[pIn->iNext],nByte,enc);
-            pIn->iNext += nByte;
+            double r;
+            assert( sizeof(double)==8 && sizeof(u64)==8 );
+            r = sqlite3_value_double(pValue);
+            memcpy(&i, &r, 8);
           }
+          sessionPutI64(&aBuf[1], i);
         }
-      }
-      if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
-        sqlite3_int64 v = sessionGetI64(aVal);
-        if( eType==SQLITE_INTEGER ){
-          sqlite3VdbeMemSetInt64(apOut[i], v);
+        nByte = 9; 
+        break;
+  
+      default: {
+        u8 *z;
+        int n;
+        int nVarint;
+  
+        assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
+        if( eType==SQLITE_TEXT ){
+          z = (u8 *)sqlite3_value_text(pValue);
         }else{
-          double d;
-          memcpy(&d, &v, 8);
-          sqlite3VdbeMemSetDouble(apOut[i], d);
+          z = (u8 *)sqlite3_value_blob(pValue);
         }
-        pIn->iNext += 8;
+        n = sqlite3_value_bytes(pValue);
+        if( z==0 && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
+        nVarint = sessionVarintLen(n);
+  
+        if( aBuf ){
+          sessionVarintPut(&aBuf[1], n);
+          if( n ) memcpy(&aBuf[nVarint + 1], z, n);
+        }
+  
+        nByte = 1 + nVarint + n;
+        break;
       }
     }
+  }else{
+    nByte = 1;
+    if( aBuf ) aBuf[0] = '\0';
   }
 
-  return rc;
+  if( pnWrite ) *pnWrite += nByte;
+  return SQLITE_OK;
 }
 
+
 /*
-** The input pointer currently points to the second byte of a table-header.
-** Specifically, to the following:
+** This macro is used to calculate hash key values for data structures. In
+** order to use this macro, the entire data structure must be represented
+** as a series of unsigned integers. In order to calculate a hash-key value
+** for a data structure represented as three such integers, the macro may
+** then be used as follows:
 **
-**   + number of columns in table (varint)
-**   + array of PK flags (1 byte per column),
-**   + table name (nul terminated).
+**    int hash_key_value;
+**    hash_key_value = HASH_APPEND(0, <value 1>);
+**    hash_key_value = HASH_APPEND(hash_key_value, <value 2>);
+**    hash_key_value = HASH_APPEND(hash_key_value, <value 3>);
 **
-** This function ensures that all of the above is present in the input 
-** buffer (i.e. that it can be accessed without any calls to xInput()).
-** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code.
-** The input pointer is not moved.
+** In practice, the data structures this macro is used for are the primary
+** key values of modified rows.
 */
-static int sessionChangesetBufferTblhdr(SessionInput *pIn, int *pnByte){
-  int rc = SQLITE_OK;
-  int nCol = 0;
-  int nRead = 0;
-
-  rc = sessionInputBuffer(pIn, 9);
-  if( rc==SQLITE_OK ){
-    nRead += sessionVarintGet(&pIn->aData[pIn->iNext + nRead], &nCol);
-    /* The hard upper limit for the number of columns in an SQLite
-    ** database table is, according to sqliteLimit.h, 32676. So 
-    ** consider any table-header that purports to have more than 65536 
-    ** columns to be corrupt. This is convenient because otherwise, 
-    ** if the (nCol>65536) condition below were omitted, a sufficiently 
-    ** large value for nCol may cause nRead to wrap around and become 
-    ** negative. Leading to a crash. */
-    if( nCol<0 || nCol>65536 ){
-      rc = SQLITE_CORRUPT_BKPT;
-    }else{
-      rc = sessionInputBuffer(pIn, nRead+nCol+100);
-      nRead += nCol;
-    }
-  }
+#define HASH_APPEND(hash, add) ((hash) << 3) ^ (hash) ^ (unsigned int)(add)
 
-  while( rc==SQLITE_OK ){
-    while( (pIn->iNext + nRead)<pIn->nData && pIn->aData[pIn->iNext + nRead] ){
-      nRead++;
-    }
-    if( (pIn->iNext + nRead)<pIn->nData ) break;
-    rc = sessionInputBuffer(pIn, nRead + 100);
-  }
-  *pnByte = nRead+1;
-  return rc;
+/*
+** Append the hash of the 64-bit integer passed as the second argument to the
+** hash-key value passed as the first. Return the new hash-key value.
+*/
+static unsigned int sessionHashAppendI64(unsigned int h, i64 i){
+  h = HASH_APPEND(h, i & 0xFFFFFFFF);
+  return HASH_APPEND(h, (i>>32)&0xFFFFFFFF);
 }
 
 /*
-** The input pointer currently points to the first byte of the first field
-** of a record consisting of nCol columns. This function ensures the entire
-** record is buffered. It does not move the input pointer.
-**
-** If successful, SQLITE_OK is returned and *pnByte is set to the size of
-** the record in bytes. Otherwise, an SQLite error code is returned. The
-** final value of *pnByte is undefined in this case.
+** Append the hash of the blob passed via the second and third arguments to 
+** the hash-key value passed as the first. Return the new hash-key value.
 */
-static int sessionChangesetBufferRecord(
-  SessionInput *pIn,              /* Input data */
-  int nCol,                       /* Number of columns in record */
-  int *pnByte                     /* OUT: Size of record in bytes */
-){
-  int rc = SQLITE_OK;
-  int nByte = 0;
+static unsigned int sessionHashAppendBlob(unsigned int h, int n, const u8 *z){
   int i;
-  for(i=0; rc==SQLITE_OK && i<nCol; i++){
-    int eType;
-    rc = sessionInputBuffer(pIn, nByte + 10);
-    if( rc==SQLITE_OK ){
-      eType = pIn->aData[pIn->iNext + nByte++];
-      if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
-        int n;
-        nByte += sessionVarintGet(&pIn->aData[pIn->iNext+nByte], &n);
-        nByte += n;
-        rc = sessionInputBuffer(pIn, nByte);
-      }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
-        nByte += 8;
-      }
-    }
-  }
-  *pnByte = nByte;
-  return rc;
+  for(i=0; i<n; i++) h = HASH_APPEND(h, z[i]);
+  return h;
 }
 
 /*
-** The input pointer currently points to the second byte of a table-header.
-** Specifically, to the following:
-**
-**   + number of columns in table (varint)
-**   + array of PK flags (1 byte per column),
-**   + table name (nul terminated).
-**
-** This function decodes the table-header and populates the p->nCol, 
-** p->zTab and p->abPK[] variables accordingly. The p->apValue[] array is 
-** also allocated or resized according to the new value of p->nCol. The
-** input pointer is left pointing to the byte following the table header.
-**
-** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code
-** is returned and the final values of the various fields enumerated above
-** are undefined.
+** Append the hash of the data type passed as the second argument to the
+** hash-key value passed as the first. Return the new hash-key value.
 */
-static int sessionChangesetReadTblhdr(sqlite3_changeset_iter *p){
-  int rc;
-  int nCopy;
-  assert( p->rc==SQLITE_OK );
-
-  rc = sessionChangesetBufferTblhdr(&p->in, &nCopy);
-  if( rc==SQLITE_OK ){
-    int nByte;
-    int nVarint;
-    nVarint = sessionVarintGet(&p->in.aData[p->in.iNext], &p->nCol);
-    if( p->nCol>0 ){
-      nCopy -= nVarint;
-      p->in.iNext += nVarint;
-      nByte = p->nCol * sizeof(sqlite3_value*) * 2 + nCopy;
-      p->tblhdr.nBuf = 0;
-      sessionBufferGrow(&p->tblhdr, nByte, &rc);
-    }else{
-      rc = SQLITE_CORRUPT_BKPT;
-    }
-  }
-
-  if( rc==SQLITE_OK ){
-    int iPK = sizeof(sqlite3_value*)*p->nCol*2;
-    memset(p->tblhdr.aBuf, 0, iPK);
-    memcpy(&p->tblhdr.aBuf[iPK], &p->in.aData[p->in.iNext], nCopy);
-    p->in.iNext += nCopy;
-  }
-
-  p->apValue = (sqlite3_value**)p->tblhdr.aBuf;
-  p->abPK = (u8*)&p->apValue[p->nCol*2];
-  p->zTab = (char*)&p->abPK[p->nCol];
-  return (p->rc = rc);
+static unsigned int sessionHashAppendType(unsigned int h, int eType){
+  return HASH_APPEND(h, eType);
 }
 
 /*
-** Advance the changeset iterator to the next change.
-**
-** If both paRec and pnRec are NULL, then this function works like the public
-** API sqlite3changeset_next(). If SQLITE_ROW is returned, then the
-** sqlite3changeset_new() and old() APIs may be used to query for values.
-**
-** Otherwise, if paRec and pnRec are not NULL, then a pointer to the change
-** record is written to *paRec before returning and the number of bytes in
-** the record to *pnRec.
+** This function may only be called from within a pre-update callback.
+** It calculates a hash based on the primary key values of the old.* or 
+** new.* row currently available and, assuming no error occurs, writes it to
+** *piHash before returning. If the primary key contains one or more NULL
+** values, *pbNullPK is set to true before returning.
 **
-** Either way, this function returns SQLITE_ROW if the iterator is 
-** successfully advanced to the next change in the changeset, an SQLite 
-** error code if an error occurs, or SQLITE_DONE if there are no further 
-** changes in the changeset.
+** If an error occurs, an SQLite error code is returned and the final values
+** of *piHash asn *pbNullPK are undefined. Otherwise, SQLITE_OK is returned
+** and the output variables are set as described above.
 */
-static int sessionChangesetNext(
-  sqlite3_changeset_iter *p,      /* Changeset iterator */
-  u8 **paRec,                     /* If non-NULL, store record pointer here */
-  int *pnRec,                     /* If non-NULL, store size of record here */
-  int *pbNew                      /* If non-NULL, true if new table */
+static int sessionPreupdateHash(
+  sqlite3_session *pSession,      /* Session object that owns pTab */
+  SessionTable *pTab,             /* Session table handle */
+  int bNew,                       /* True to hash the new.* PK */
+  int *piHash,                    /* OUT: Hash value */
+  int *pbNullPK                   /* OUT: True if there are NULL values in PK */
 ){
-  int i;
-  u8 op;
-
-  assert( (paRec==0 && pnRec==0) || (paRec && pnRec) );
-
-  /* If the iterator is in the error-state, return immediately. */
-  if( p->rc!=SQLITE_OK ) return p->rc;
-
-  /* Free the current contents of p->apValue[], if any. */
-  if( p->apValue ){
-    for(i=0; i<p->nCol*2; i++){
-      sqlite3ValueFree(p->apValue[i]);
-    }
-    memset(p->apValue, 0, sizeof(sqlite3_value*)*p->nCol*2);
-  }
-
-  /* Make sure the buffer contains at least 10 bytes of input data, or all
-  ** remaining data if there are less than 10 bytes available. This is
-  ** sufficient either for the 'T' or 'P' byte and the varint that follows
-  ** it, or for the two single byte values otherwise. */
-  p->rc = sessionInputBuffer(&p->in, 2);
-  if( p->rc!=SQLITE_OK ) return p->rc;
-
-  /* If the iterator is already at the end of the changeset, return DONE. */
-  if( p->in.iNext>=p->in.nData ){
-    return SQLITE_DONE;
-  }
-
-  sessionDiscardData(&p->in);
-  p->in.iCurrent = p->in.iNext;
-
-  op = p->in.aData[p->in.iNext++];
-  while( op=='T' || op=='P' ){
-    if( pbNew ) *pbNew = 1;
-    p->bPatchset = (op=='P');
-    if( sessionChangesetReadTblhdr(p) ) return p->rc;
-    if( (p->rc = sessionInputBuffer(&p->in, 2)) ) return p->rc;
-    p->in.iCurrent = p->in.iNext;
-    if( p->in.iNext>=p->in.nData ) return SQLITE_DONE;
-    op = p->in.aData[p->in.iNext++];
-  }
-
-  if( p->zTab==0 ){
-    /* The first record in the changeset is not a table header. Must be a
-    ** corrupt changeset. */
-    assert( p->in.iNext==1 );
-    return (p->rc = SQLITE_CORRUPT_BKPT);
-  }
-
-  p->op = op;
-  p->bIndirect = p->in.aData[p->in.iNext++];
-  if( p->op!=SQLITE_UPDATE && p->op!=SQLITE_DELETE && p->op!=SQLITE_INSERT ){
-    return (p->rc = SQLITE_CORRUPT_BKPT);
-  }
-
-  if( paRec ){ 
-    int nVal;                     /* Number of values to buffer */
-    if( p->bPatchset==0 && op==SQLITE_UPDATE ){
-      nVal = p->nCol * 2;
-    }else if( p->bPatchset && op==SQLITE_DELETE ){
-      nVal = 0;
-      for(i=0; i<p->nCol; i++) if( p->abPK[i] ) nVal++;
-    }else{
-      nVal = p->nCol;
-    }
-    p->rc = sessionChangesetBufferRecord(&p->in, nVal, pnRec);
-    if( p->rc!=SQLITE_OK ) return p->rc;
-    *paRec = &p->in.aData[p->in.iNext];
-    p->in.iNext += *pnRec;
-  }else{
+  unsigned int h = 0;             /* Hash value to return */
+  int i;                          /* Used to iterate through columns */
 
-    /* If this is an UPDATE or DELETE, read the old.* record. */
-    if( p->op!=SQLITE_INSERT && (p->bPatchset==0 || p->op==SQLITE_DELETE) ){
-      u8 *abPK = p->bPatchset ? p->abPK : 0;
-      p->rc = sessionReadRecord(&p->in, p->nCol, abPK, p->apValue);
-      if( p->rc!=SQLITE_OK ) return p->rc;
-    }
+  assert( *pbNullPK==0 );
+  assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) );
+  for(i=0; i<pTab->nCol; i++){
+    if( pTab->abPK[i] ){
+      int rc;
+      int eType;
+      sqlite3_value *pVal;
 
-    /* If this is an INSERT or UPDATE, read the new.* record. */
-    if( p->op!=SQLITE_DELETE ){
-      p->rc = sessionReadRecord(&p->in, p->nCol, 0, &p->apValue[p->nCol]);
-      if( p->rc!=SQLITE_OK ) return p->rc;
-    }
+      if( bNew ){
+        rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal);
+      }else{
+        rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal);
+      }
+      if( rc!=SQLITE_OK ) return rc;
 
-    if( p->bPatchset && p->op==SQLITE_UPDATE ){
-      /* If this is an UPDATE that is part of a patchset, then all PK and
-      ** modified fields are present in the new.* record. The old.* record
-      ** is currently completely empty. This block shifts the PK fields from
-      ** new.* to old.*, to accommodate the code that reads these arrays.  */
-      for(i=0; i<p->nCol; i++){
-        assert( p->apValue[i]==0 );
-        if( p->abPK[i] ){
-          p->apValue[i] = p->apValue[i+p->nCol];
-          if( p->apValue[i]==0 ) return (p->rc = SQLITE_CORRUPT_BKPT);
-          p->apValue[i+p->nCol] = 0;
+      eType = sqlite3_value_type(pVal);
+      h = sessionHashAppendType(h, eType);
+      if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+        i64 iVal;
+        if( eType==SQLITE_INTEGER ){
+          iVal = sqlite3_value_int64(pVal);
+        }else{
+          double rVal = sqlite3_value_double(pVal);
+          assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
+          memcpy(&iVal, &rVal, 8);
+        }
+        h = sessionHashAppendI64(h, iVal);
+      }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
+        const u8 *z;
+        int n;
+        if( eType==SQLITE_TEXT ){
+          z = (const u8 *)sqlite3_value_text(pVal);
+        }else{
+          z = (const u8 *)sqlite3_value_blob(pVal);
         }
+        n = sqlite3_value_bytes(pVal);
+        if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
+        h = sessionHashAppendBlob(h, n, z);
+      }else{
+        assert( eType==SQLITE_NULL );
+        assert( pTab->bStat1==0 || i!=1 );
+        *pbNullPK = 1;
       }
     }
   }
 
-  return SQLITE_ROW;
-}
-
-/*
-** Advance an iterator created by sqlite3changeset_start() to the next
-** change in the changeset. This function may return SQLITE_ROW, SQLITE_DONE
-** or SQLITE_CORRUPT.
-**
-** This function may not be called on iterators passed to a conflict handler
-** callback by changeset_apply().
-*/
-SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *p){
-  return sessionChangesetNext(p, 0, 0, 0);
-}
-
-/*
-** The following function extracts information on the current change
-** from a changeset iterator. It may only be called after changeset_next()
-** has returned SQLITE_ROW.
-*/
-SQLITE_API int sqlite3changeset_op(
-  sqlite3_changeset_iter *pIter,  /* Iterator handle */
-  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 if change is indirect */
-){
-  *pOp = pIter->op;
-  *pnCol = pIter->nCol;
-  *pzTab = pIter->zTab;
-  if( pbIndirect ) *pbIndirect = pIter->bIndirect;
+  *piHash = (h % pTab->nChange);
   return SQLITE_OK;
 }
 
 /*
-** Return information regarding the PRIMARY KEY and number of columns in
-** the database table affected by the change that pIter currently points
-** to. This function may only be called after changeset_next() returns
-** SQLITE_ROW.
+** The buffer that the argument points to contains a serialized SQL value.
+** Return the number of bytes of space occupied by the value (including
+** the type byte).
 */
-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 */
-){
-  *pabPK = pIter->abPK;
-  if( pnCol ) *pnCol = pIter->nCol;
-  return SQLITE_OK;
+static int sessionSerialLen(u8 *a){
+  int e = *a;
+  int n;
+  if( e==0 || e==0xFF ) return 1;
+  if( e==SQLITE_NULL ) return 1;
+  if( e==SQLITE_INTEGER || e==SQLITE_FLOAT ) return 9;
+  return sessionVarintGet(&a[1], &n) + 1 + n;
 }
 
 /*
-** This function may only be called while the iterator is pointing to an
-** SQLITE_UPDATE or SQLITE_DELETE change (see sqlite3changeset_op()).
-** Otherwise, SQLITE_MISUSE is returned.
-**
-** It sets *ppValue to point to an sqlite3_value structure containing the
-** iVal'th value in the old.* record. Or, if that particular value is not
-** included in the record (because the change is an UPDATE and the field
-** was not modified and is not a PK column), set *ppValue to NULL.
+** Based on the primary key values stored in change aRecord, calculate a
+** hash key. Assume the has table has nBucket buckets. The hash keys
+** calculated by this function are compatible with those calculated by
+** sessionPreupdateHash().
 **
-** If value iVal is out-of-range, SQLITE_RANGE is returned and *ppValue is
-** not modified. Otherwise, SQLITE_OK.
+** The bPkOnly argument is non-zero if the record at aRecord[] is from
+** a patchset DELETE. In this case the non-PK fields are omitted entirely.
 */
-SQLITE_API int sqlite3changeset_old(
-  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
-  int iVal,                       /* Index of old.* value to retrieve */
-  sqlite3_value **ppValue         /* OUT: Old value (or NULL pointer) */
+static unsigned int sessionChangeHash(
+  SessionTable *pTab,             /* Table handle */
+  int bPkOnly,                    /* Record consists of PK fields only */
+  u8 *aRecord,                    /* Change record */
+  int nBucket                     /* Assume this many buckets in hash table */
 ){
-  if( pIter->op!=SQLITE_UPDATE && pIter->op!=SQLITE_DELETE ){
-    return SQLITE_MISUSE;
-  }
-  if( iVal<0 || iVal>=pIter->nCol ){
-    return SQLITE_RANGE;
-  }
-  *ppValue = pIter->apValue[iVal];
-  return SQLITE_OK;
-}
+  unsigned int h = 0;             /* Value to return */
+  int i;                          /* Used to iterate through columns */
+  u8 *a = aRecord;                /* Used to iterate through change record */
 
-/*
-** This function may only be called while the iterator is pointing to an
-** SQLITE_UPDATE or SQLITE_INSERT change (see sqlite3changeset_op()).
-** Otherwise, SQLITE_MISUSE is returned.
-**
-** It sets *ppValue to point to an sqlite3_value structure containing the
-** iVal'th value in the new.* record. Or, if that particular value is not
-** included in the record (because the change is an UPDATE and the field
-** was not modified), set *ppValue to NULL.
-**
-** If value iVal is out-of-range, SQLITE_RANGE is returned and *ppValue is
-** not modified. Otherwise, SQLITE_OK.
-*/
-SQLITE_API int sqlite3changeset_new(
-  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
-  int iVal,                       /* Index of new.* value to retrieve */
-  sqlite3_value **ppValue         /* OUT: New value (or NULL pointer) */
-){
-  if( pIter->op!=SQLITE_UPDATE && pIter->op!=SQLITE_INSERT ){
-    return SQLITE_MISUSE;
-  }
-  if( iVal<0 || iVal>=pIter->nCol ){
-    return SQLITE_RANGE;
-  }
-  *ppValue = pIter->apValue[pIter->nCol+iVal];
-  return SQLITE_OK;
-}
+  for(i=0; i<pTab->nCol; i++){
+    int eType = *a;
+    int isPK = pTab->abPK[i];
+    if( bPkOnly && isPK==0 ) continue;
 
-/*
-** The following two macros are used internally. They are similar to the
-** sqlite3changeset_new() and sqlite3changeset_old() functions, except that
-** they omit all error checking and return a pointer to the requested value.
-*/
-#define sessionChangesetNew(pIter, iVal) (pIter)->apValue[(pIter)->nCol+(iVal)]
-#define sessionChangesetOld(pIter, iVal) (pIter)->apValue[(iVal)]
+    /* It is not possible for eType to be SQLITE_NULL here. The session 
+    ** module does not record changes for rows with NULL values stored in
+    ** primary key columns. */
+    assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT 
+         || eType==SQLITE_TEXT || eType==SQLITE_BLOB 
+         || eType==SQLITE_NULL || eType==0 
+    );
+    assert( !isPK || (eType!=0 && eType!=SQLITE_NULL) );
 
-/*
-** This function may only be called with a changeset iterator that has been
-** passed to an SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT 
-** conflict-handler function. Otherwise, SQLITE_MISUSE is returned.
-**
-** If successful, *ppValue is set to point to an sqlite3_value structure
-** containing the iVal'th value of the conflicting record.
-**
-** If value iVal is out-of-range or some other error occurs, an SQLite error
-** code is returned. Otherwise, SQLITE_OK.
-*/
-SQLITE_API int sqlite3changeset_conflict(
-  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
-  int iVal,                       /* Index of conflict record value to fetch */
-  sqlite3_value **ppValue         /* OUT: Value from conflicting row */
-){
-  if( !pIter->pConflict ){
-    return SQLITE_MISUSE;
-  }
-  if( iVal<0 || iVal>=pIter->nCol ){
-    return SQLITE_RANGE;
+    if( isPK ){
+      a++;
+      h = sessionHashAppendType(h, eType);
+      if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+        h = sessionHashAppendI64(h, sessionGetI64(a));
+        a += 8;
+      }else{
+        int n; 
+        a += sessionVarintGet(a, &n);
+        h = sessionHashAppendBlob(h, n, a);
+        a += n;
+      }
+    }else{
+      a += sessionSerialLen(a);
+    }
   }
-  *ppValue = sqlite3_column_value(pIter->pConflict, iVal);
-  return SQLITE_OK;
+  return (h % nBucket);
 }
 
 /*
-** 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.
+** Arguments aLeft and aRight are pointers to change records for table pTab.
+** This function returns true if the two records apply to the same row (i.e.
+** have the same values stored in the primary key columns), or false 
+** otherwise.
 */
-SQLITE_API int sqlite3changeset_fk_conflicts(
-  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
-  int *pnOut                      /* OUT: Number of FK violations */
+static int sessionChangeEqual(
+  SessionTable *pTab,             /* Table used for PK definition */
+  int bLeftPkOnly,                /* True if aLeft[] contains PK fields only */
+  u8 *aLeft,                      /* Change record */
+  int bRightPkOnly,               /* True if aRight[] contains PK fields only */
+  u8 *aRight                      /* Change record */
 ){
-  if( pIter->pConflict || pIter->apValue ){
-    return SQLITE_MISUSE;
+  u8 *a1 = aLeft;                 /* Cursor to iterate through aLeft */
+  u8 *a2 = aRight;                /* Cursor to iterate through aRight */
+  int iCol;                       /* Used to iterate through table columns */
+
+  for(iCol=0; iCol<pTab->nCol; iCol++){
+    if( pTab->abPK[iCol] ){
+      int n1 = sessionSerialLen(a1);
+      int n2 = sessionSerialLen(a2);
+
+      if( n1!=n2 || memcmp(a1, a2, n1) ){
+        return 0;
+      }
+      a1 += n1;
+      a2 += n2;
+    }else{
+      if( bLeftPkOnly==0 ) a1 += sessionSerialLen(a1);
+      if( bRightPkOnly==0 ) a2 += sessionSerialLen(a2);
+    }
   }
-  *pnOut = pIter->nCol;
-  return SQLITE_OK;
-}
 
+  return 1;
+}
 
 /*
-** Finalize an iterator allocated with sqlite3changeset_start().
+** Arguments aLeft and aRight both point to buffers containing change
+** records with nCol columns. This function "merges" the two records into
+** a single records which is written to the buffer at *paOut. *paOut is
+** then set to point to one byte after the last byte written before 
+** returning.
 **
-** This function may not be called on iterators passed to a conflict handler
-** callback by changeset_apply().
+** The merging of records is done as follows: For each column, if the 
+** aRight record contains a value for the column, copy the value from
+** their. Otherwise, if aLeft contains a value, copy it. If neither
+** record contains a value for a given column, then neither does the
+** output record.
 */
-SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *p){
-  int rc = SQLITE_OK;
-  if( p ){
-    int i;                        /* Used to iterate through p->apValue[] */
-    rc = p->rc;
-    if( p->apValue ){
-      for(i=0; i<p->nCol*2; i++) sqlite3ValueFree(p->apValue[i]);
+static void sessionMergeRecord(
+  u8 **paOut, 
+  int nCol,
+  u8 *aLeft,
+  u8 *aRight
+){
+  u8 *a1 = aLeft;                 /* Cursor used to iterate through aLeft */
+  u8 *a2 = aRight;                /* Cursor used to iterate through aRight */
+  u8 *aOut = *paOut;              /* Output cursor */
+  int iCol;                       /* Used to iterate from 0 to nCol */
+
+  for(iCol=0; iCol<nCol; iCol++){
+    int n1 = sessionSerialLen(a1);
+    int n2 = sessionSerialLen(a2);
+    if( *a2 ){
+      memcpy(aOut, a2, n2);
+      aOut += n2;
+    }else{
+      memcpy(aOut, a1, n1);
+      aOut += n1;
     }
-    sqlite3_free(p->tblhdr.aBuf);
-    sqlite3_free(p->in.buf.aBuf);
-    sqlite3_free(p);
+    a1 += n1;
+    a2 += n2;
   }
-  return rc;
+
+  *paOut = aOut;
 }
 
-static int sessionChangesetInvert(
-  SessionInput *pInput,           /* Input changeset */
-  int (*xOutput)(void *pOut, const void *pData, int nData),
-  void *pOut,
-  int *pnInverted,                /* OUT: Number of bytes in output changeset */
-  void **ppInverted               /* OUT: Inverse of pChangeset */
+/*
+** This is a helper function used by sessionMergeUpdate().
+**
+** When this function is called, both *paOne and *paTwo point to a value 
+** within a change record. Before it returns, both have been advanced so 
+** as to point to the next value in the record.
+**
+** If, when this function is called, *paTwo points to a valid value (i.e.
+** *paTwo[0] is not 0x00 - the "no value" placeholder), a copy of the *paTwo
+** pointer is returned and *pnVal is set to the number of bytes in the 
+** serialized value. Otherwise, a copy of *paOne is returned and *pnVal
+** set to the number of bytes in the value at *paOne. If *paOne points
+** to the "no value" placeholder, *pnVal is set to 1. In other words:
+**
+**   if( *paTwo is valid ) return *paTwo;
+**   return *paOne;
+**
+*/
+static u8 *sessionMergeValue(
+  u8 **paOne,                     /* IN/OUT: Left-hand buffer pointer */
+  u8 **paTwo,                     /* IN/OUT: Right-hand buffer pointer */
+  int *pnVal                      /* OUT: Bytes in returned value */
 ){
-  int rc = SQLITE_OK;             /* Return value */
-  SessionBuffer sOut;             /* Output buffer */
-  int nCol = 0;                   /* Number of cols in current table */
-  u8 *abPK = 0;                   /* PK array for current table */
-  sqlite3_value **apVal = 0;      /* Space for values for UPDATE inversion */
-  SessionBuffer sPK = {0, 0, 0};  /* PK array for current table */
-
-  /* Initialize the output buffer */
-  memset(&sOut, 0, sizeof(SessionBuffer));
+  u8 *a1 = *paOne;
+  u8 *a2 = *paTwo;
+  u8 *pRet = 0;
+  int n1;
 
-  /* Zero the output variables in case an error occurs. */
-  if( ppInverted ){
-    *ppInverted = 0;
-    *pnInverted = 0;
+  assert( a1 );
+  if( a2 ){
+    int n2 = sessionSerialLen(a2);
+    if( *a2 ){
+      *pnVal = n2;
+      pRet = a2;
+    }
+    *paTwo = &a2[n2];
   }
 
-  while( 1 ){
-    u8 eType;
-
-    /* Test for EOF. */
-    if( (rc = sessionInputBuffer(pInput, 2)) ) goto finished_invert;
-    if( pInput->iNext>=pInput->nData ) break;
-    eType = pInput->aData[pInput->iNext];
-
-    switch( eType ){
-      case 'T': {
-        /* A 'table' record consists of:
-        **
-        **   * A constant 'T' character,
-        **   * Number of columns in said table (a varint),
-        **   * An array of nCol bytes (sPK),
-        **   * A nul-terminated table name.
-        */
-        int nByte;
-        int nVar;
-        pInput->iNext++;
-        if( (rc = sessionChangesetBufferTblhdr(pInput, &nByte)) ){
-          goto finished_invert;
-        }
-        nVar = sessionVarintGet(&pInput->aData[pInput->iNext], &nCol);
-        sPK.nBuf = 0;
-        sessionAppendBlob(&sPK, &pInput->aData[pInput->iNext+nVar], nCol, &rc);
-        sessionAppendByte(&sOut, eType, &rc);
-        sessionAppendBlob(&sOut, &pInput->aData[pInput->iNext], nByte, &rc);
-        if( rc ) goto finished_invert;
-
-        pInput->iNext += nByte;
-        sqlite3_free(apVal);
-        apVal = 0;
-        abPK = sPK.aBuf;
-        break;
-      }
-
-      case SQLITE_INSERT:
-      case SQLITE_DELETE: {
-        int nByte;
-        int bIndirect = pInput->aData[pInput->iNext+1];
-        int eType2 = (eType==SQLITE_DELETE ? SQLITE_INSERT : SQLITE_DELETE);
-        pInput->iNext += 2;
-        assert( rc==SQLITE_OK );
-        rc = sessionChangesetBufferRecord(pInput, nCol, &nByte);
-        sessionAppendByte(&sOut, eType2, &rc);
-        sessionAppendByte(&sOut, bIndirect, &rc);
-        sessionAppendBlob(&sOut, &pInput->aData[pInput->iNext], nByte, &rc);
-        pInput->iNext += nByte;
-        if( rc ) goto finished_invert;
-        break;
-      }
-
-      case SQLITE_UPDATE: {
-        int iCol;
+  n1 = sessionSerialLen(a1);
+  if( pRet==0 ){
+    *pnVal = n1;
+    pRet = a1;
+  }
+  *paOne = &a1[n1];
 
-        if( 0==apVal ){
-          apVal = (sqlite3_value **)sqlite3_malloc(sizeof(apVal[0])*nCol*2);
-          if( 0==apVal ){
-            rc = SQLITE_NOMEM;
-            goto finished_invert;
-          }
-          memset(apVal, 0, sizeof(apVal[0])*nCol*2);
-        }
+  return pRet;
+}
 
-        /* Write the header for the new UPDATE change. Same as the original. */
-        sessionAppendByte(&sOut, eType, &rc);
-        sessionAppendByte(&sOut, pInput->aData[pInput->iNext+1], &rc);
+/*
+** This function is used by changeset_concat() to merge two UPDATE changes
+** on the same row.
+*/
+static int sessionMergeUpdate(
+  u8 **paOut,                     /* IN/OUT: Pointer to output buffer */
+  SessionTable *pTab,             /* Table change pertains to */
+  int bPatchset,                  /* True if records are patchset records */
+  u8 *aOldRecord1,                /* old.* record for first change */
+  u8 *aOldRecord2,                /* old.* record for second change */
+  u8 *aNewRecord1,                /* new.* record for first change */
+  u8 *aNewRecord2                 /* new.* record for second change */
+){
+  u8 *aOld1 = aOldRecord1;
+  u8 *aOld2 = aOldRecord2;
+  u8 *aNew1 = aNewRecord1;
+  u8 *aNew2 = aNewRecord2;
 
-        /* Read the old.* and new.* records for the update change. */
-        pInput->iNext += 2;
-        rc = sessionReadRecord(pInput, nCol, 0, &apVal[0]);
-        if( rc==SQLITE_OK ){
-          rc = sessionReadRecord(pInput, nCol, 0, &apVal[nCol]);
-        }
+  u8 *aOut = *paOut;
+  int i;
 
-        /* Write the new old.* record. Consists of the PK columns from the
-        ** original old.* record, and the other values from the original
-        ** new.* record. */
-        for(iCol=0; iCol<nCol; iCol++){
-          sqlite3_value *pVal = apVal[iCol + (abPK[iCol] ? 0 : nCol)];
-          sessionAppendValue(&sOut, pVal, &rc);
-        }
+  if( bPatchset==0 ){
+    int bRequired = 0;
 
-        /* Write the new new.* record. Consists of a copy of all values
-        ** from the original old.* record, except for the PK columns, which
-        ** are set to "undefined". */
-        for(iCol=0; iCol<nCol; iCol++){
-          sqlite3_value *pVal = (abPK[iCol] ? 0 : apVal[iCol]);
-          sessionAppendValue(&sOut, pVal, &rc);
-        }
+    assert( aOldRecord1 && aNewRecord1 );
 
-        for(iCol=0; iCol<nCol*2; iCol++){
-          sqlite3ValueFree(apVal[iCol]);
-        }
-        memset(apVal, 0, sizeof(apVal[0])*nCol*2);
-        if( rc!=SQLITE_OK ){
-          goto finished_invert;
-        }
+    /* Write the old.* vector first. */
+    for(i=0; i<pTab->nCol; i++){
+      int nOld;
+      u8 *aOld;
+      int nNew;
+      u8 *aNew;
 
-        break;
+      aOld = sessionMergeValue(&aOld1, &aOld2, &nOld);
+      aNew = sessionMergeValue(&aNew1, &aNew2, &nNew);
+      if( pTab->abPK[i] || nOld!=nNew || memcmp(aOld, aNew, nNew) ){
+        if( pTab->abPK[i]==0 ) bRequired = 1;
+        memcpy(aOut, aOld, nOld);
+        aOut += nOld;
+      }else{
+        *(aOut++) = '\0';
       }
-
-      default:
-        rc = SQLITE_CORRUPT_BKPT;
-        goto finished_invert;
     }
 
-    assert( rc==SQLITE_OK );
-    if( xOutput && sOut.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){
-      rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
-      sOut.nBuf = 0;
-      if( rc!=SQLITE_OK ) goto finished_invert;
-    }
+    if( !bRequired ) return 0;
   }
 
-  assert( rc==SQLITE_OK );
-  if( pnInverted ){
-    *pnInverted = sOut.nBuf;
-    *ppInverted = sOut.aBuf;
-    sOut.aBuf = 0;
-  }else if( sOut.nBuf>0 ){
-    rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
+  /* Write the new.* vector */
+  aOld1 = aOldRecord1;
+  aOld2 = aOldRecord2;
+  aNew1 = aNewRecord1;
+  aNew2 = aNewRecord2;
+  for(i=0; i<pTab->nCol; i++){
+    int nOld;
+    u8 *aOld;
+    int nNew;
+    u8 *aNew;
+
+    aOld = sessionMergeValue(&aOld1, &aOld2, &nOld);
+    aNew = sessionMergeValue(&aNew1, &aNew2, &nNew);
+    if( bPatchset==0 
+     && (pTab->abPK[i] || (nOld==nNew && 0==memcmp(aOld, aNew, nNew))) 
+    ){
+      *(aOut++) = '\0';
+    }else{
+      memcpy(aOut, aNew, nNew);
+      aOut += nNew;
+    }
   }
 
- finished_invert:
-  sqlite3_free(sOut.aBuf);
-  sqlite3_free(apVal);
-  sqlite3_free(sPK.aBuf);
-  return rc;
+  *paOut = aOut;
+  return 1;
 }
 
-
 /*
-** Invert a changeset object.
+** This function is only called from within a pre-update-hook callback.
+** It determines if the current pre-update-hook change affects the same row
+** as the change stored in argument pChange. If so, it returns true. Otherwise
+** if the pre-update-hook does not affect the same row as pChange, it returns
+** false.
 */
-SQLITE_API int sqlite3changeset_invert(
-  int nChangeset,                 /* Number of bytes in input */
-  const void *pChangeset,         /* Input changeset */
-  int *pnInverted,                /* OUT: Number of bytes in output changeset */
-  void **ppInverted               /* OUT: Inverse of pChangeset */
+static int sessionPreupdateEqual(
+  sqlite3_session *pSession,      /* Session object that owns SessionTable */
+  SessionTable *pTab,             /* Table associated with change */
+  SessionChange *pChange,         /* Change to compare to */
+  int op                          /* Current pre-update operation */
 ){
-  SessionInput sInput;
+  int iCol;                       /* Used to iterate through columns */
+  u8 *a = pChange->aRecord;       /* Cursor used to scan change record */
 
-  /* Set up the input stream */
-  memset(&sInput, 0, sizeof(SessionInput));
-  sInput.nData = nChangeset;
-  sInput.aData = (u8*)pChangeset;
+  assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE );
+  for(iCol=0; iCol<pTab->nCol; iCol++){
+    if( !pTab->abPK[iCol] ){
+      a += sessionSerialLen(a);
+    }else{
+      sqlite3_value *pVal;        /* Value returned by preupdate_new/old */
+      int rc;                     /* Error code from preupdate_new/old */
+      int eType = *a++;           /* Type of value from change record */
 
-  return sessionChangesetInvert(&sInput, 0, 0, pnInverted, ppInverted);
-}
+      /* The following calls to preupdate_new() and preupdate_old() can not
+      ** fail. This is because they cache their return values, and by the
+      ** time control flows to here they have already been called once from
+      ** within sessionPreupdateHash(). The first two asserts below verify
+      ** this (that the method has already been called). */
+      if( op==SQLITE_INSERT ){
+        /* assert( db->pPreUpdate->pNewUnpacked || db->pPreUpdate->aNew ); */
+        rc = pSession->hook.xNew(pSession->hook.pCtx, iCol, &pVal);
+      }else{
+        /* assert( db->pPreUpdate->pUnpacked ); */
+        rc = pSession->hook.xOld(pSession->hook.pCtx, iCol, &pVal);
+      }
+      assert( rc==SQLITE_OK );
+      if( sqlite3_value_type(pVal)!=eType ) return 0;
 
-/*
-** Streaming version of sqlite3changeset_invert().
-*/
-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
-){
-  SessionInput sInput;
-  int rc;
+      /* A SessionChange object never has a NULL value in a PK column */
+      assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT
+           || eType==SQLITE_BLOB    || eType==SQLITE_TEXT
+      );
 
-  /* Set up the input stream */
-  memset(&sInput, 0, sizeof(SessionInput));
-  sInput.xInput = xInput;
-  sInput.pIn = pIn;
+      if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+        i64 iVal = sessionGetI64(a);
+        a += 8;
+        if( eType==SQLITE_INTEGER ){
+          if( sqlite3_value_int64(pVal)!=iVal ) return 0;
+        }else{
+          double rVal;
+          assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
+          memcpy(&rVal, &iVal, 8);
+          if( sqlite3_value_double(pVal)!=rVal ) return 0;
+        }
+      }else{
+        int n;
+        const u8 *z;
+        a += sessionVarintGet(a, &n);
+        if( sqlite3_value_bytes(pVal)!=n ) return 0;
+        if( eType==SQLITE_TEXT ){
+          z = sqlite3_value_text(pVal);
+        }else{
+          z = sqlite3_value_blob(pVal);
+        }
+        if( n>0 && memcmp(a, z, n) ) return 0;
+        a += n;
+      }
+    }
+  }
 
-  rc = sessionChangesetInvert(&sInput, xOutput, pOut, 0, 0);
-  sqlite3_free(sInput.buf.aBuf);
-  return rc;
+  return 1;
 }
 
-typedef struct SessionApplyCtx SessionApplyCtx;
-struct SessionApplyCtx {
-  sqlite3 *db;
-  sqlite3_stmt *pDelete;          /* DELETE statement */
-  sqlite3_stmt *pUpdate;          /* UPDATE statement */
-  sqlite3_stmt *pInsert;          /* INSERT statement */
-  sqlite3_stmt *pSelect;          /* SELECT statement */
-  int nCol;                       /* Size of azCol[] and abPK[] arrays */
-  const char **azCol;             /* Array of column names */
-  u8 *abPK;                       /* Boolean array - true if column is in PK */
-  int bStat1;                     /* True if table is sqlite_stat1 */
-  int bDeferConstraints;          /* True to defer constraints */
-  SessionBuffer constraints;      /* Deferred constraints are stored here */
-  SessionBuffer rebase;           /* Rebase information (if any) here */
-  int bRebaseStarted;             /* If table header is already in rebase */
-};
-
 /*
-** Formulate a statement to DELETE a row from database db. Assuming a table
-** structure like this:
-**
-**     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
-**
-** The DELETE statement looks like this:
-**
-**     DELETE FROM x WHERE a = :1 AND c = :3 AND (:5 OR b IS :2 AND d IS :4)
-**
-** Variable :5 (nCol+1) is a boolean. It should be set to 0 if we require
-** matching b and d values, or 1 otherwise. The second case comes up if the
-** conflict handler is invoked with NOTFOUND and returns CHANGESET_REPLACE.
+** If required, grow the hash table used to store changes on table pTab 
+** (part of the session pSession). If a fatal OOM error occurs, set the
+** session object to failed and return SQLITE_ERROR. Otherwise, return
+** SQLITE_OK.
 **
-** If successful, SQLITE_OK is returned and SessionApplyCtx.pDelete is left
-** pointing to the prepared version of the SQL statement.
+** It is possible that a non-fatal OOM error occurs in this function. In
+** that case the hash-table does not grow, but SQLITE_OK is returned anyway.
+** Growing the hash table in this case is a performance optimization only,
+** it is not required for correct operation.
 */
-static int sessionDeleteRow(
-  sqlite3 *db,                    /* Database handle */
-  const char *zTab,               /* Table name */
-  SessionApplyCtx *p              /* Session changeset-apply context */
-){
-  int i;
-  const char *zSep = "";
-  int rc = SQLITE_OK;
-  SessionBuffer buf = {0, 0, 0};
-  int nPk = 0;
-
-  sessionAppendStr(&buf, "DELETE FROM ", &rc);
-  sessionAppendIdent(&buf, zTab, &rc);
-  sessionAppendStr(&buf, " WHERE ", &rc);
+static int sessionGrowHash(int bPatchset, SessionTable *pTab){
+  if( pTab->nChange==0 || pTab->nEntry>=(pTab->nChange/2) ){
+    int i;
+    SessionChange **apNew;
+    int nNew = (pTab->nChange ? pTab->nChange : 128) * 2;
 
-  for(i=0; i<p->nCol; i++){
-    if( p->abPK[i] ){
-      nPk++;
-      sessionAppendStr(&buf, zSep, &rc);
-      sessionAppendIdent(&buf, p->azCol[i], &rc);
-      sessionAppendStr(&buf, " = ?", &rc);
-      sessionAppendInteger(&buf, i+1, &rc);
-      zSep = " AND ";
+    apNew = (SessionChange **)sqlite3_malloc(sizeof(SessionChange *) * nNew);
+    if( apNew==0 ){
+      if( pTab->nChange==0 ){
+        return SQLITE_ERROR;
+      }
+      return SQLITE_OK;
     }
-  }
-
-  if( nPk<p->nCol ){
-    sessionAppendStr(&buf, " AND (?", &rc);
-    sessionAppendInteger(&buf, p->nCol+1, &rc);
-    sessionAppendStr(&buf, " OR ", &rc);
+    memset(apNew, 0, sizeof(SessionChange *) * nNew);
 
-    zSep = "";
-    for(i=0; i<p->nCol; i++){
-      if( !p->abPK[i] ){
-        sessionAppendStr(&buf, zSep, &rc);
-        sessionAppendIdent(&buf, p->azCol[i], &rc);
-        sessionAppendStr(&buf, " IS ?", &rc);
-        sessionAppendInteger(&buf, i+1, &rc);
-        zSep = "AND ";
+    for(i=0; i<pTab->nChange; i++){
+      SessionChange *p;
+      SessionChange *pNext;
+      for(p=pTab->apChange[i]; p; p=pNext){
+        int bPkOnly = (p->op==SQLITE_DELETE && bPatchset);
+        int iHash = sessionChangeHash(pTab, bPkOnly, p->aRecord, nNew);
+        pNext = p->pNext;
+        p->pNext = apNew[iHash];
+        apNew[iHash] = p;
       }
     }
-    sessionAppendStr(&buf, ")", &rc);
-  }
 
-  if( rc==SQLITE_OK ){
-    rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pDelete, 0);
+    sqlite3_free(pTab->apChange);
+    pTab->nChange = nNew;
+    pTab->apChange = apNew;
   }
-  sqlite3_free(buf.aBuf);
 
-  return rc;
+  return SQLITE_OK;
 }
 
 /*
-** Formulate and prepare a statement to UPDATE a row from database db. 
-** Assuming a table structure like this:
-**
-**     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
+** This function queries the database for the names of the columns of table
+** zThis, in schema zDb.
 **
-** The UPDATE statement looks like this:
+** Otherwise, if they are not NULL, variable *pnCol is set to the number
+** of columns in the database table and variable *pzTab is set to point to a
+** nul-terminated copy of the table name. *pazCol (if not NULL) is set to
+** point to an array of pointers to column names. And *pabPK (again, if not
+** NULL) is set to point to an array of booleans - true if the corresponding
+** column is part of the primary key.
 **
-**     UPDATE x SET
-**     a = CASE WHEN ?2  THEN ?3  ELSE a END,
-**     b = CASE WHEN ?5  THEN ?6  ELSE b END,
-**     c = CASE WHEN ?8  THEN ?9  ELSE c END,
-**     d = CASE WHEN ?11 THEN ?12 ELSE d END
-**     WHERE a = ?1 AND c = ?7 AND (?13 OR 
-**       (?5==0 OR b IS ?4) AND (?11==0 OR d IS ?10) AND
-**     )
+** For example, if the table is declared as:
 **
-** For each column in the table, there are three variables to bind:
+**     CREATE TABLE tbl1(w, x, y, z, PRIMARY KEY(w, z));
 **
-**     ?(i*3+1)    The old.* value of the column, if any.
-**     ?(i*3+2)    A boolean flag indicating that the value is being modified.
-**     ?(i*3+3)    The new.* value of the column, if any.
+** Then the four output variables are populated as follows:
 **
-** Also, a boolean flag that, if set to true, causes the statement to update
-** a row even if the non-PK values do not match. This is required if the
-** conflict-handler is invoked with CHANGESET_DATA and returns
-** CHANGESET_REPLACE. This is variable "?(nCol*3+1)".
+**     *pnCol  = 4
+**     *pzTab  = "tbl1"
+**     *pazCol = {"w", "x", "y", "z"}
+**     *pabPK  = {1, 0, 0, 1}
 **
-** If successful, SQLITE_OK is returned and SessionApplyCtx.pUpdate is left
-** pointing to the prepared version of the SQL statement.
+** All returned buffers are part of the same single allocation, which must
+** be freed using sqlite3_free() by the caller
 */
-static int sessionUpdateRow(
-  sqlite3 *db,                    /* Database handle */
-  const char *zTab,               /* Table name */
-  SessionApplyCtx *p              /* Session changeset-apply context */
+static int sessionTableInfo(
+  sqlite3 *db,                    /* Database connection */
+  const char *zDb,                /* Name of attached database (e.g. "main") */
+  const char *zThis,              /* Table name */
+  int *pnCol,                     /* OUT: number of columns */
+  const char **pzTab,             /* OUT: Copy of zThis */
+  const char ***pazCol,           /* OUT: Array of column names for table */
+  u8 **pabPK                      /* OUT: Array of booleans - true for PK col */
 ){
-  int rc = SQLITE_OK;
+  char *zPragma;
+  sqlite3_stmt *pStmt;
+  int rc;
+  int nByte;
+  int nDbCol = 0;
+  int nThis;
   int i;
-  const char *zSep = "";
-  SessionBuffer buf = {0, 0, 0};
+  u8 *pAlloc = 0;
+  char **azCol = 0;
+  u8 *abPK = 0;
 
-  /* Append "UPDATE tbl SET " */
-  sessionAppendStr(&buf, "UPDATE ", &rc);
-  sessionAppendIdent(&buf, zTab, &rc);
-  sessionAppendStr(&buf, " SET ", &rc);
+  assert( pazCol && pabPK );
 
-  /* Append the assignments */
-  for(i=0; i<p->nCol; i++){
-    sessionAppendStr(&buf, zSep, &rc);
-    sessionAppendIdent(&buf, p->azCol[i], &rc);
-    sessionAppendStr(&buf, " = CASE WHEN ?", &rc);
-    sessionAppendInteger(&buf, i*3+2, &rc);
-    sessionAppendStr(&buf, " THEN ?", &rc);
-    sessionAppendInteger(&buf, i*3+3, &rc);
-    sessionAppendStr(&buf, " ELSE ", &rc);
-    sessionAppendIdent(&buf, p->azCol[i], &rc);
-    sessionAppendStr(&buf, " END", &rc);
-    zSep = ", ";
+  nThis = sqlite3Strlen30(zThis);
+  if( nThis==12 && 0==sqlite3_stricmp("sqlite_stat1", zThis) ){
+    rc = sqlite3_table_column_metadata(db, zDb, zThis, 0, 0, 0, 0, 0, 0);
+    if( rc==SQLITE_OK ){
+      /* For sqlite_stat1, pretend that (tbl,idx) is the PRIMARY KEY. */
+      zPragma = sqlite3_mprintf(
+          "SELECT 0, 'tbl',  '', 0, '', 1     UNION ALL "
+          "SELECT 1, 'idx',  '', 0, '', 2     UNION ALL "
+          "SELECT 2, 'stat', '', 0, '', 0"
+      );
+    }else if( rc==SQLITE_ERROR ){
+      zPragma = sqlite3_mprintf("");
+    }else{
+      return rc;
+    }
+  }else{
+    zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
   }
+  if( !zPragma ) return SQLITE_NOMEM;
 
-  /* Append the PK part of the WHERE clause */
-  sessionAppendStr(&buf, " WHERE ", &rc);
-  for(i=0; i<p->nCol; i++){
-    if( p->abPK[i] ){
-      sessionAppendIdent(&buf, p->azCol[i], &rc);
-      sessionAppendStr(&buf, " = ?", &rc);
-      sessionAppendInteger(&buf, i*3+1, &rc);
-      sessionAppendStr(&buf, " AND ", &rc);
-    }
+  rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0);
+  sqlite3_free(zPragma);
+  if( rc!=SQLITE_OK ) return rc;
+
+  nByte = nThis + 1;
+  while( SQLITE_ROW==sqlite3_step(pStmt) ){
+    nByte += sqlite3_column_bytes(pStmt, 1);
+    nDbCol++;
   }
+  rc = sqlite3_reset(pStmt);
 
-  /* Append the non-PK part of the WHERE clause */
-  sessionAppendStr(&buf, " (?", &rc);
-  sessionAppendInteger(&buf, p->nCol*3+1, &rc);
-  sessionAppendStr(&buf, " OR 1", &rc);
-  for(i=0; i<p->nCol; i++){
-    if( !p->abPK[i] ){
-      sessionAppendStr(&buf, " AND (?", &rc);
-      sessionAppendInteger(&buf, i*3+2, &rc);
-      sessionAppendStr(&buf, "=0 OR ", &rc);
-      sessionAppendIdent(&buf, p->azCol[i], &rc);
-      sessionAppendStr(&buf, " IS ?", &rc);
-      sessionAppendInteger(&buf, i*3+1, &rc);
-      sessionAppendStr(&buf, ")", &rc);
+  if( rc==SQLITE_OK ){
+    nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
+    pAlloc = sqlite3_malloc(nByte);
+    if( pAlloc==0 ){
+      rc = SQLITE_NOMEM;
     }
   }
-  sessionAppendStr(&buf, ")", &rc);
-
   if( rc==SQLITE_OK ){
-    rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pUpdate, 0);
+    azCol = (char **)pAlloc;
+    pAlloc = (u8 *)&azCol[nDbCol];
+    abPK = (u8 *)pAlloc;
+    pAlloc = &abPK[nDbCol];
+    if( pzTab ){
+      memcpy(pAlloc, zThis, nThis+1);
+      *pzTab = (char *)pAlloc;
+      pAlloc += nThis+1;
+    }
+  
+    i = 0;
+    while( SQLITE_ROW==sqlite3_step(pStmt) ){
+      int nName = sqlite3_column_bytes(pStmt, 1);
+      const unsigned char *zName = sqlite3_column_text(pStmt, 1);
+      if( zName==0 ) break;
+      memcpy(pAlloc, zName, nName+1);
+      azCol[i] = (char *)pAlloc;
+      pAlloc += nName+1;
+      abPK[i] = sqlite3_column_int(pStmt, 5);
+      i++;
+    }
+    rc = sqlite3_reset(pStmt);
+  
   }
-  sqlite3_free(buf.aBuf);
 
+  /* If successful, populate the output variables. Otherwise, zero them and
+  ** free any allocation made. An error code will be returned in this case.
+  */
+  if( rc==SQLITE_OK ){
+    *pazCol = (const char **)azCol;
+    *pabPK = abPK;
+    *pnCol = nDbCol;
+  }else{
+    *pazCol = 0;
+    *pabPK = 0;
+    *pnCol = 0;
+    if( pzTab ) *pzTab = 0;
+    sqlite3_free(azCol);
+  }
+  sqlite3_finalize(pStmt);
   return rc;
 }
 
-
 /*
-** Formulate and prepare an SQL statement to query table zTab by primary
-** key. Assuming the following table structure:
-**
-**     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
-**
-** The SELECT statement looks like this:
-**
-**     SELECT * FROM x WHERE a = ?1 AND c = ?3
+** This function is only called from within a pre-update handler for a
+** write to table pTab, part of session pSession. If this is the first
+** write to this table, initalize the SessionTable.nCol, azCol[] and
+** abPK[] arrays accordingly.
 **
-** If successful, SQLITE_OK is returned and SessionApplyCtx.pSelect is left
-** pointing to the prepared version of the SQL statement.
+** If an error occurs, an error code is stored in sqlite3_session.rc and
+** non-zero returned. Or, if no error occurs but the table has no primary
+** key, sqlite3_session.rc is left set to SQLITE_OK and non-zero returned to
+** indicate that updates on this table should be ignored. SessionTable.abPK 
+** is set to NULL in this case.
 */
-static int sessionSelectRow(
-  sqlite3 *db,                    /* Database handle */
-  const char *zTab,               /* Table name */
-  SessionApplyCtx *p              /* Session changeset-apply context */
-){
-  return sessionSelectStmt(
-      db, "main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect);
+static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
+  if( pTab->nCol==0 ){
+    u8 *abPK;
+    assert( pTab->azCol==0 || pTab->abPK==0 );
+    pSession->rc = sessionTableInfo(pSession->db, pSession->zDb, 
+        pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK
+    );
+    if( pSession->rc==SQLITE_OK ){
+      int i;
+      for(i=0; i<pTab->nCol; i++){
+        if( abPK[i] ){
+          pTab->abPK = abPK;
+          break;
+        }
+      }
+      if( 0==sqlite3_stricmp("sqlite_stat1", pTab->zName) ){
+        pTab->bStat1 = 1;
+      }
+    }
+  }
+  return (pSession->rc || pTab->abPK==0);
 }
 
 /*
-** Formulate and prepare an INSERT statement to add a record to table zTab.
-** For example:
-**
-**     INSERT INTO main."zTab" VALUES(?1, ?2, ?3 ...);
-**
-** If successful, SQLITE_OK is returned and SessionApplyCtx.pInsert is left
-** pointing to the prepared version of the SQL statement.
+** Versions of the four methods in object SessionHook for use with the
+** sqlite_stat1 table. The purpose of this is to substitute a zero-length
+** blob each time a NULL value is read from the "idx" column of the
+** sqlite_stat1 table.
 */
-static int sessionInsertRow(
-  sqlite3 *db,                    /* Database handle */
-  const char *zTab,               /* Table name */
-  SessionApplyCtx *p              /* Session changeset-apply context */
-){
-  int rc = SQLITE_OK;
-  int i;
-  SessionBuffer buf = {0, 0, 0};
-
-  sessionAppendStr(&buf, "INSERT INTO main.", &rc);
-  sessionAppendIdent(&buf, zTab, &rc);
-  sessionAppendStr(&buf, "(", &rc);
-  for(i=0; i<p->nCol; i++){
-    if( i!=0 ) sessionAppendStr(&buf, ", ", &rc);
-    sessionAppendIdent(&buf, p->azCol[i], &rc);
-  }
-
-  sessionAppendStr(&buf, ") VALUES(?", &rc);
-  for(i=1; i<p->nCol; i++){
-    sessionAppendStr(&buf, ", ?", &rc);
+typedef struct SessionStat1Ctx SessionStat1Ctx;
+struct SessionStat1Ctx {
+  SessionHook hook;
+  sqlite3_session *pSession;
+};
+static int sessionStat1Old(void *pCtx, int iCol, sqlite3_value **ppVal){
+  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
+  sqlite3_value *pVal = 0;
+  int rc = p->hook.xOld(p->hook.pCtx, iCol, &pVal);
+  if( rc==SQLITE_OK && iCol==1 && sqlite3_value_type(pVal)==SQLITE_NULL ){
+    pVal = p->pSession->pZeroBlob;
   }
-  sessionAppendStr(&buf, ")", &rc);
-
-  if( rc==SQLITE_OK ){
-    rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pInsert, 0);
+  *ppVal = pVal;
+  return rc;
+}
+static int sessionStat1New(void *pCtx, int iCol, sqlite3_value **ppVal){
+  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
+  sqlite3_value *pVal = 0;
+  int rc = p->hook.xNew(p->hook.pCtx, iCol, &pVal);
+  if( rc==SQLITE_OK && iCol==1 && sqlite3_value_type(pVal)==SQLITE_NULL ){
+    pVal = p->pSession->pZeroBlob;
   }
-  sqlite3_free(buf.aBuf);
+  *ppVal = pVal;
   return rc;
 }
-
-static int sessionPrepare(sqlite3 *db, sqlite3_stmt **pp, const char *zSql){
-  return sqlite3_prepare_v2(db, zSql, -1, pp, 0);
+static int sessionStat1Count(void *pCtx){
+  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
+  return p->hook.xCount(p->hook.pCtx);
+}
+static int sessionStat1Depth(void *pCtx){
+  SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx;
+  return p->hook.xDepth(p->hook.pCtx);
 }
 
+
 /*
-** Prepare statements for applying changes to the sqlite_stat1 table.
-** These are similar to those created by sessionSelectRow(),
-** sessionInsertRow(), sessionUpdateRow() and sessionDeleteRow() for 
-** other tables.
+** This function is only called from with a pre-update-hook reporting a 
+** change on table pTab (attached to session pSession). The type of change
+** (UPDATE, INSERT, DELETE) is specified by the first argument.
+**
+** Unless one is already present or an error occurs, an entry is added
+** to the changed-rows hash table associated with table pTab.
 */
-static int sessionStat1Sql(sqlite3 *db, SessionApplyCtx *p){
-  int rc = sessionSelectRow(db, "sqlite_stat1", p);
-  if( rc==SQLITE_OK ){
-    rc = sessionPrepare(db, &p->pInsert,
-        "INSERT INTO main.sqlite_stat1 VALUES(?1, "
-        "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END, "
-        "?3)"
-    );
+static void sessionPreupdateOneChange(
+  int op,                         /* One of SQLITE_UPDATE, INSERT, DELETE */
+  sqlite3_session *pSession,      /* Session object pTab is attached to */
+  SessionTable *pTab              /* Table that change applies to */
+){
+  int iHash; 
+  int bNull = 0; 
+  int rc = SQLITE_OK;
+  SessionStat1Ctx stat1 = {0};
+
+  if( pSession->rc ) return;
+
+  /* Load table details if required */
+  if( sessionInitTable(pSession, pTab) ) return;
+
+  /* Check the number of columns in this xPreUpdate call matches the 
+  ** number of columns in the table.  */
+  if( pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) ){
+    pSession->rc = SQLITE_SCHEMA;
+    return;
   }
-  if( rc==SQLITE_OK ){
-    rc = sessionPrepare(db, &p->pUpdate,
-        "UPDATE main.sqlite_stat1 SET "
-        "tbl = CASE WHEN ?2 THEN ?3 ELSE tbl END, "
-        "idx = CASE WHEN ?5 THEN ?6 ELSE idx END, "
-        "stat = CASE WHEN ?8 THEN ?9 ELSE stat END  "
-        "WHERE tbl=?1 AND idx IS "
-        "CASE WHEN length(?4)=0 AND typeof(?4)='blob' THEN NULL ELSE ?4 END "
-        "AND (?10 OR ?8=0 OR stat IS ?7)"
-    );
+
+  /* Grow the hash table if required */
+  if( sessionGrowHash(0, pTab) ){
+    pSession->rc = SQLITE_NOMEM;
+    return;
   }
-  if( rc==SQLITE_OK ){
-    rc = sessionPrepare(db, &p->pDelete,
-        "DELETE FROM main.sqlite_stat1 WHERE tbl=?1 AND idx IS "
-        "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END "
-        "AND (?4 OR stat IS ?3)"
-    );
+
+  if( pTab->bStat1 ){
+    stat1.hook = pSession->hook;
+    stat1.pSession = pSession;
+    pSession->hook.pCtx = (void*)&stat1;
+    pSession->hook.xNew = sessionStat1New;
+    pSession->hook.xOld = sessionStat1Old;
+    pSession->hook.xCount = sessionStat1Count;
+    pSession->hook.xDepth = sessionStat1Depth;
+    if( pSession->pZeroBlob==0 ){
+      sqlite3_value *p = sqlite3ValueNew(0);
+      if( p==0 ){
+        rc = SQLITE_NOMEM;
+        goto error_out;
+      }
+      sqlite3ValueSetStr(p, 0, "", 0, SQLITE_STATIC);
+      pSession->pZeroBlob = p;
+    }
   }
-  return rc;
-}
 
-/*
-** A wrapper around sqlite3_bind_value() that detects an extra problem. 
-** See comments in the body of this function for details.
-*/
-static int sessionBindValue(
-  sqlite3_stmt *pStmt,            /* Statement to bind value to */
-  int i,                          /* Parameter number to bind to */
-  sqlite3_value *pVal             /* Value to bind */
-){
-  int eType = sqlite3_value_type(pVal);
-  /* COVERAGE: The (pVal->z==0) branch is never true using current versions
-  ** of SQLite. If a malloc fails in an sqlite3_value_xxx() function, either
-  ** the (pVal->z) variable remains as it was or the type of the value is
-  ** set to SQLITE_NULL.  */
-  if( (eType==SQLITE_TEXT || eType==SQLITE_BLOB) && pVal->z==0 ){
-    /* This condition occurs when an earlier OOM in a call to
-    ** sqlite3_value_text() or sqlite3_value_blob() (perhaps from within
-    ** a conflict-handler) has zeroed the pVal->z pointer. Return NOMEM. */
-    return SQLITE_NOMEM;
+  /* Calculate the hash-key for this change. If the primary key of the row
+  ** includes a NULL value, exit early. Such changes are ignored by the
+  ** session module. */
+  rc = sessionPreupdateHash(pSession, pTab, op==SQLITE_INSERT, &iHash, &bNull);
+  if( rc!=SQLITE_OK ) goto error_out;
+
+  if( bNull==0 ){
+    /* Search the hash table for an existing record for this row. */
+    SessionChange *pC;
+    for(pC=pTab->apChange[iHash]; pC; pC=pC->pNext){
+      if( sessionPreupdateEqual(pSession, pTab, pC, op) ) break;
+    }
+
+    if( pC==0 ){
+      /* Create a new change object containing all the old values (if
+      ** this is an SQLITE_UPDATE or SQLITE_DELETE), or just the PK
+      ** values (if this is an INSERT). */
+      SessionChange *pChange; /* New change object */
+      int nByte;              /* Number of bytes to allocate */
+      int i;                  /* Used to iterate through columns */
+  
+      assert( rc==SQLITE_OK );
+      pTab->nEntry++;
+  
+      /* Figure out how large an allocation is required */
+      nByte = sizeof(SessionChange);
+      for(i=0; i<pTab->nCol; i++){
+        sqlite3_value *p = 0;
+        if( op!=SQLITE_INSERT ){
+          TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p);
+          assert( trc==SQLITE_OK );
+        }else if( pTab->abPK[i] ){
+          TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx, i, &p);
+          assert( trc==SQLITE_OK );
+        }
+
+        /* This may fail if SQLite value p contains a utf-16 string that must
+        ** be converted to utf-8 and an OOM error occurs while doing so. */
+        rc = sessionSerializeValue(0, p, &nByte);
+        if( rc!=SQLITE_OK ) goto error_out;
+      }
+  
+      /* Allocate the change object */
+      pChange = (SessionChange *)sqlite3_malloc(nByte);
+      if( !pChange ){
+        rc = SQLITE_NOMEM;
+        goto error_out;
+      }else{
+        memset(pChange, 0, sizeof(SessionChange));
+        pChange->aRecord = (u8 *)&pChange[1];
+      }
+  
+      /* Populate the change object. None of the preupdate_old(),
+      ** preupdate_new() or SerializeValue() calls below may fail as all
+      ** required values and encodings have already been cached in memory.
+      ** It is not possible for an OOM to occur in this block. */
+      nByte = 0;
+      for(i=0; i<pTab->nCol; i++){
+        sqlite3_value *p = 0;
+        if( op!=SQLITE_INSERT ){
+          pSession->hook.xOld(pSession->hook.pCtx, i, &p);
+        }else if( pTab->abPK[i] ){
+          pSession->hook.xNew(pSession->hook.pCtx, i, &p);
+        }
+        sessionSerializeValue(&pChange->aRecord[nByte], p, &nByte);
+      }
+
+      /* Add the change to the hash-table */
+      if( pSession->bIndirect || pSession->hook.xDepth(pSession->hook.pCtx) ){
+        pChange->bIndirect = 1;
+      }
+      pChange->nRecord = nByte;
+      pChange->op = op;
+      pChange->pNext = pTab->apChange[iHash];
+      pTab->apChange[iHash] = pChange;
+
+    }else if( pC->bIndirect ){
+      /* If the existing change is considered "indirect", but this current
+      ** change is "direct", mark the change object as direct. */
+      if( pSession->hook.xDepth(pSession->hook.pCtx)==0 
+       && pSession->bIndirect==0 
+      ){
+        pC->bIndirect = 0;
+      }
+    }
+  }
+
+  /* If an error has occurred, mark the session object as failed. */
+ error_out:
+  if( pTab->bStat1 ){
+    pSession->hook = stat1.hook;
+  }
+  if( rc!=SQLITE_OK ){
+    pSession->rc = rc;
   }
-  return sqlite3_bind_value(pStmt, i, pVal);
 }
 
-/*
-** Iterator pIter must point to an SQLITE_INSERT entry. This function 
-** transfers new.* values from the current iterator entry to statement
-** pStmt. The table being inserted into has nCol columns.
-**
-** New.* value $i from the iterator is bound to variable ($i+1) of 
-** statement pStmt. If parameter abPK is NULL, all values from 0 to (nCol-1)
-** are transfered to the statement. Otherwise, if abPK is not NULL, it points
-** to an array nCol elements in size. In this case only those values for 
-** which abPK[$i] is true are read from the iterator and bound to the 
-** statement.
-**
-** An SQLite error code is returned if an error occurs. Otherwise, SQLITE_OK.
-*/
-static int sessionBindRow(
-  sqlite3_changeset_iter *pIter,  /* Iterator to read values from */
-  int(*xValue)(sqlite3_changeset_iter *, int, sqlite3_value **),
-  int nCol,                       /* Number of columns */
-  u8 *abPK,                       /* If not NULL, bind only if true */
-  sqlite3_stmt *pStmt             /* Bind values to this statement */
+static int sessionFindTable(
+  sqlite3_session *pSession, 
+  const char *zName,
+  SessionTable **ppTab
 ){
-  int i;
   int rc = SQLITE_OK;
+  int nName = sqlite3Strlen30(zName);
+  SessionTable *pRet;
 
-  /* Neither sqlite3changeset_old or sqlite3changeset_new can fail if the
-  ** argument iterator points to a suitable entry. Make sure that xValue 
-  ** is one of these to guarantee that it is safe to ignore the return 
-  ** in the code below. */
-  assert( xValue==sqlite3changeset_old || xValue==sqlite3changeset_new );
+  /* Search for an existing table */
+  for(pRet=pSession->pTable; pRet; pRet=pRet->pNext){
+    if( 0==sqlite3_strnicmp(pRet->zName, zName, nName+1) ) break;
+  }
 
-  for(i=0; rc==SQLITE_OK && i<nCol; i++){
-    if( !abPK || abPK[i] ){
-      sqlite3_value *pVal;
-      (void)xValue(pIter, i, &pVal);
-      if( pVal==0 ){
-        /* The value in the changeset was "undefined". This indicates a
-        ** corrupt changeset blob.  */
-        rc = SQLITE_CORRUPT_BKPT;
-      }else{
-        rc = sessionBindValue(pStmt, i+1, pVal);
+  if( pRet==0 && pSession->bAutoAttach ){
+    /* If there is a table-filter configured, invoke it. If it returns 0,
+    ** do not automatically add the new table. */
+    if( pSession->xTableFilter==0
+     || pSession->xTableFilter(pSession->pFilterCtx, zName) 
+    ){
+      rc = sqlite3session_attach(pSession, zName);
+      if( rc==SQLITE_OK ){
+        for(pRet=pSession->pTable; pRet->pNext; pRet=pRet->pNext);
+        assert( 0==sqlite3_strnicmp(pRet->zName, zName, nName+1) );
       }
     }
   }
+
+  assert( rc==SQLITE_OK || pRet==0 );
+  *ppTab = pRet;
   return rc;
 }
 
 /*
-** SQL statement pSelect is as generated by the sessionSelectRow() function.
-** This function binds the primary key values from the change that changeset
-** iterator pIter points to to the SELECT and attempts to seek to the table
-** entry. If a row is found, the SELECT statement left pointing at the row 
-** and SQLITE_ROW is returned. Otherwise, if no row is found and no error
-** has occured, the statement is reset and SQLITE_OK is returned. If an
-** error occurs, the statement is reset and an SQLite error code is returned.
-**
-** If this function returns SQLITE_ROW, the caller must eventually reset() 
-** statement pSelect. If any other value is returned, the statement does
-** not require a reset().
-**
-** If the iterator currently points to an INSERT record, bind values from the
-** new.* record to the SELECT statement. Or, if it points to a DELETE or
-** UPDATE, bind values from the old.* record. 
+** The 'pre-update' hook registered by this module with SQLite databases.
 */
-static int sessionSeekToRow(
+static void xPreUpdate(
+  void *pCtx,                     /* Copy of third arg to preupdate_hook() */
   sqlite3 *db,                    /* Database handle */
-  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
-  u8 *abPK,                       /* Primary key flags array */
-  sqlite3_stmt *pSelect           /* SELECT statement from sessionSelectRow() */
+  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) */
 ){
-  int rc;                         /* Return code */
-  int nCol;                       /* Number of columns in table */
-  int op;                         /* Changset operation (SQLITE_UPDATE etc.) */
-  const char *zDummy;             /* Unused */
+  sqlite3_session *pSession;
+  int nDb = sqlite3Strlen30(zDb);
 
-  sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
-  rc = sessionBindRow(pIter, 
-      op==SQLITE_INSERT ? sqlite3changeset_new : sqlite3changeset_old,
-      nCol, abPK, pSelect
-  );
+  assert( sqlite3_mutex_held(db->mutex) );
 
-  if( rc==SQLITE_OK ){
-    rc = sqlite3_step(pSelect);
-    if( rc!=SQLITE_ROW ) rc = sqlite3_reset(pSelect);
+  for(pSession=(sqlite3_session *)pCtx; pSession; pSession=pSession->pNext){
+    SessionTable *pTab;
+
+    /* If this session is attached to a different database ("main", "temp" 
+    ** etc.), or if it is not currently enabled, there is nothing to do. Skip 
+    ** to the next session object attached to this database. */
+    if( pSession->bEnable==0 ) continue;
+    if( pSession->rc ) continue;
+    if( sqlite3_strnicmp(zDb, pSession->zDb, nDb+1) ) continue;
+
+    pSession->rc = sessionFindTable(pSession, zName, &pTab);
+    if( pTab ){
+      assert( pSession->rc==SQLITE_OK );
+      sessionPreupdateOneChange(op, pSession, pTab);
+      if( op==SQLITE_UPDATE ){
+        sessionPreupdateOneChange(SQLITE_INSERT, pSession, pTab);
+      }
+    }
   }
+}
 
-  return rc;
+/*
+** The pre-update hook implementations.
+*/
+static int sessionPreupdateOld(void *pCtx, int iVal, sqlite3_value **ppVal){
+  return sqlite3_preupdate_old((sqlite3*)pCtx, iVal, ppVal);
+}
+static int sessionPreupdateNew(void *pCtx, int iVal, sqlite3_value **ppVal){
+  return sqlite3_preupdate_new((sqlite3*)pCtx, iVal, ppVal);
+}
+static int sessionPreupdateCount(void *pCtx){
+  return sqlite3_preupdate_count((sqlite3*)pCtx);
+}
+static int sessionPreupdateDepth(void *pCtx){
+  return sqlite3_preupdate_depth((sqlite3*)pCtx);
 }
 
 /*
-** This function is called from within sqlite3changset_apply_v2() when
-** a conflict is encountered and resolved using conflict resolution
-** mode eType (either SQLITE_CHANGESET_OMIT or SQLITE_CHANGESET_REPLACE)..
-** It adds a conflict resolution record to the buffer in 
-** SessionApplyCtx.rebase, which will eventually be returned to the caller
-** of apply_v2() as the "rebase" buffer.
-**
-** Return SQLITE_OK if successful, or an SQLite error code otherwise.
+** Install the pre-update hooks on the session object passed as the only
+** argument.
 */
-static int sessionRebaseAdd(
-  SessionApplyCtx *p,             /* Apply context */
-  int eType,                      /* Conflict resolution (OMIT or REPLACE) */
-  sqlite3_changeset_iter *pIter   /* Iterator pointing at current change */
+static void sessionPreupdateHooks(
+  sqlite3_session *pSession
 ){
-  int rc = SQLITE_OK;
-  int i;
-  int eOp = pIter->op;
-  if( p->bRebaseStarted==0 ){
-    /* Append a table-header to the rebase buffer */
-    const char *zTab = pIter->zTab;
-    sessionAppendByte(&p->rebase, 'T', &rc);
-    sessionAppendVarint(&p->rebase, p->nCol, &rc);
-    sessionAppendBlob(&p->rebase, p->abPK, p->nCol, &rc);
-    sessionAppendBlob(&p->rebase, (u8*)zTab, (int)strlen(zTab)+1, &rc);
-    p->bRebaseStarted = 1;
-  }
-
-  assert( eType==SQLITE_CHANGESET_REPLACE||eType==SQLITE_CHANGESET_OMIT );
-  assert( eOp==SQLITE_DELETE || eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE );
+  pSession->hook.pCtx = (void*)pSession->db;
+  pSession->hook.xOld = sessionPreupdateOld;
+  pSession->hook.xNew = sessionPreupdateNew;
+  pSession->hook.xCount = sessionPreupdateCount;
+  pSession->hook.xDepth = sessionPreupdateDepth;
+}
 
-  sessionAppendByte(&p->rebase, 
-      (eOp==SQLITE_DELETE ? SQLITE_DELETE : SQLITE_INSERT), &rc
-  );
-  sessionAppendByte(&p->rebase, (eType==SQLITE_CHANGESET_REPLACE), &rc);
-  for(i=0; i<p->nCol; i++){
-    sqlite3_value *pVal = 0;
-    if( eOp==SQLITE_DELETE || (eOp==SQLITE_UPDATE && p->abPK[i]) ){
-      sqlite3changeset_old(pIter, i, &pVal);
-    }else{
-      sqlite3changeset_new(pIter, i, &pVal);
-    }
-    sessionAppendValue(&p->rebase, pVal, &rc);
-  }
+typedef struct SessionDiffCtx SessionDiffCtx;
+struct SessionDiffCtx {
+  sqlite3_stmt *pStmt;
+  int nOldOff;
+};
 
-  return rc;
+/*
+** The diff hook implementations.
+*/
+static int sessionDiffOld(void *pCtx, int iVal, sqlite3_value **ppVal){
+  SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
+  *ppVal = sqlite3_column_value(p->pStmt, iVal+p->nOldOff);
+  return SQLITE_OK;
+}
+static int sessionDiffNew(void *pCtx, int iVal, sqlite3_value **ppVal){
+  SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
+  *ppVal = sqlite3_column_value(p->pStmt, iVal);
+   return SQLITE_OK;
+}
+static int sessionDiffCount(void *pCtx){
+  SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
+  return p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt);
+}
+static int sessionDiffDepth(void *pCtx){
+  return 0;
 }
 
 /*
-** Invoke the conflict handler for the change that the changeset iterator
-** currently points to.
-**
-** Argument eType must be either CHANGESET_DATA or CHANGESET_CONFLICT.
-** If argument pbReplace is NULL, then the type of conflict handler invoked
-** depends solely on eType, as follows:
-**
-**    eType value                 Value passed to xConflict
-**    -------------------------------------------------
-**    CHANGESET_DATA              CHANGESET_NOTFOUND
-**    CHANGESET_CONFLICT          CHANGESET_CONSTRAINT
-**
-** Or, if pbReplace is not NULL, then an attempt is made to find an existing
-** record with the same primary key as the record about to be deleted, updated
-** or inserted. If such a record can be found, it is available to the conflict
-** handler as the "conflicting" record. In this case the type of conflict
-** handler invoked is as follows:
-**
-**    eType value         PK Record found?   Value passed to xConflict
-**    ----------------------------------------------------------------
-**    CHANGESET_DATA      Yes                CHANGESET_DATA
-**    CHANGESET_DATA      No                 CHANGESET_NOTFOUND
-**    CHANGESET_CONFLICT  Yes                CHANGESET_CONFLICT
-**    CHANGESET_CONFLICT  No                 CHANGESET_CONSTRAINT
-**
-** If pbReplace is not NULL, and a record with a matching PK is found, and
-** the conflict handler function returns SQLITE_CHANGESET_REPLACE, *pbReplace
-** is set to non-zero before returning SQLITE_OK.
-**
-** If the conflict handler returns SQLITE_CHANGESET_ABORT, SQLITE_ABORT is
-** returned. Or, if the conflict handler returns an invalid value, 
-** SQLITE_MISUSE. If the conflict handler returns SQLITE_CHANGESET_OMIT,
-** this function returns SQLITE_OK.
+** Install the diff hooks on the session object passed as the only
+** argument.
 */
-static int sessionConflictHandler(
-  int eType,                      /* Either CHANGESET_DATA or CONFLICT */
-  SessionApplyCtx *p,             /* changeset_apply() context */
-  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
-  int(*xConflict)(void *, int, sqlite3_changeset_iter*),
-  void *pCtx,                     /* First argument for conflict handler */
-  int *pbReplace                  /* OUT: Set to true if PK row is found */
+static void sessionDiffHooks(
+  sqlite3_session *pSession,
+  SessionDiffCtx *pDiffCtx
 ){
-  int res = 0;                    /* Value returned by conflict handler */
-  int rc;
-  int nCol;
-  int op;
-  const char *zDummy;
-
-  sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
+  pSession->hook.pCtx = (void*)pDiffCtx;
+  pSession->hook.xOld = sessionDiffOld;
+  pSession->hook.xNew = sessionDiffNew;
+  pSession->hook.xCount = sessionDiffCount;
+  pSession->hook.xDepth = sessionDiffDepth;
+}
 
-  assert( eType==SQLITE_CHANGESET_CONFLICT || eType==SQLITE_CHANGESET_DATA );
-  assert( SQLITE_CHANGESET_CONFLICT+1==SQLITE_CHANGESET_CONSTRAINT );
-  assert( SQLITE_CHANGESET_DATA+1==SQLITE_CHANGESET_NOTFOUND );
+static char *sessionExprComparePK(
+  int nCol,
+  const char *zDb1, const char *zDb2, 
+  const char *zTab,
+  const char **azCol, u8 *abPK
+){
+  int i;
+  const char *zSep = "";
+  char *zRet = 0;
 
-  /* Bind the new.* PRIMARY KEY values to the SELECT statement. */
-  if( pbReplace ){
-    rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect);
-  }else{
-    rc = SQLITE_OK;
+  for(i=0; i<nCol; i++){
+    if( abPK[i] ){
+      zRet = sqlite3_mprintf("%z%s\"%w\".\"%w\".\"%w\"=\"%w\".\"%w\".\"%w\"",
+          zRet, zSep, zDb1, zTab, azCol[i], zDb2, zTab, azCol[i]
+      );
+      zSep = " AND ";
+      if( zRet==0 ) break;
+    }
   }
 
-  if( rc==SQLITE_ROW ){
-    /* There exists another row with the new.* primary key. */
-    pIter->pConflict = p->pSelect;
-    res = xConflict(pCtx, eType, pIter);
-    pIter->pConflict = 0;
-    rc = sqlite3_reset(p->pSelect);
-  }else if( rc==SQLITE_OK ){
-    if( p->bDeferConstraints && eType==SQLITE_CHANGESET_CONFLICT ){
-      /* Instead of invoking the conflict handler, append the change blob
-      ** to the SessionApplyCtx.constraints buffer. */
-      u8 *aBlob = &pIter->in.aData[pIter->in.iCurrent];
-      int nBlob = pIter->in.iNext - pIter->in.iCurrent;
-      sessionAppendBlob(&p->constraints, aBlob, nBlob, &rc);
-      return SQLITE_OK;
-    }else{
-      /* No other row with the new.* primary key. */
-      res = xConflict(pCtx, eType+1, pIter);
-      if( res==SQLITE_CHANGESET_REPLACE ) rc = SQLITE_MISUSE;
+  return zRet;
+}
+
+static char *sessionExprCompareOther(
+  int nCol,
+  const char *zDb1, const char *zDb2, 
+  const char *zTab,
+  const char **azCol, u8 *abPK
+){
+  int i;
+  const char *zSep = "";
+  char *zRet = 0;
+  int bHave = 0;
+
+  for(i=0; i<nCol; i++){
+    if( abPK[i]==0 ){
+      bHave = 1;
+      zRet = sqlite3_mprintf(
+          "%z%s\"%w\".\"%w\".\"%w\" IS NOT \"%w\".\"%w\".\"%w\"",
+          zRet, zSep, zDb1, zTab, azCol[i], zDb2, zTab, azCol[i]
+      );
+      zSep = " OR ";
+      if( zRet==0 ) break;
     }
   }
 
-  if( rc==SQLITE_OK ){
-    switch( res ){
-      case SQLITE_CHANGESET_REPLACE:
-        assert( pbReplace );
-        *pbReplace = 1;
-        break;
+  if( bHave==0 ){
+    assert( zRet==0 );
+    zRet = sqlite3_mprintf("0");
+  }
 
-      case SQLITE_CHANGESET_OMIT:
-        break;
+  return zRet;
+}
 
-      case SQLITE_CHANGESET_ABORT:
-        rc = SQLITE_ABORT;
-        break;
+static char *sessionSelectFindNew(
+  int nCol,
+  const char *zDb1,      /* Pick rows in this db only */
+  const char *zDb2,      /* But not in this one */
+  const char *zTbl,      /* Table name */
+  const char *zExpr
+){
+  char *zRet = sqlite3_mprintf(
+      "SELECT * FROM \"%w\".\"%w\" WHERE NOT EXISTS ("
+      "  SELECT 1 FROM \"%w\".\"%w\" WHERE %s"
+      ")",
+      zDb1, zTbl, zDb2, zTbl, zExpr
+  );
+  return zRet;
+}
 
-      default:
-        rc = SQLITE_MISUSE;
-        break;
-    }
+static int sessionDiffFindNew(
+  int op,
+  sqlite3_session *pSession,
+  SessionTable *pTab,
+  const char *zDb1,
+  const char *zDb2,
+  char *zExpr
+){
+  int rc = SQLITE_OK;
+  char *zStmt = sessionSelectFindNew(pTab->nCol, zDb1, zDb2, pTab->zName,zExpr);
+
+  if( zStmt==0 ){
+    rc = SQLITE_NOMEM;
+  }else{
+    sqlite3_stmt *pStmt;
+    rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0);
     if( rc==SQLITE_OK ){
-      rc = sessionRebaseAdd(p, res, pIter);
+      SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx;
+      pDiffCtx->pStmt = pStmt;
+      pDiffCtx->nOldOff = 0;
+      while( SQLITE_ROW==sqlite3_step(pStmt) ){
+        sessionPreupdateOneChange(op, pSession, pTab);
+      }
+      rc = sqlite3_finalize(pStmt);
     }
+    sqlite3_free(zStmt);
   }
 
   return rc;
 }
 
-/*
-** Attempt to apply the change that the iterator passed as the first argument
-** currently points to to the database. If a conflict is encountered, invoke
-** the conflict handler callback.
-**
-** If argument pbRetry is NULL, then ignore any CHANGESET_DATA conflict. If
-** one is encountered, update or delete the row with the matching primary key
-** instead. Or, if pbRetry is not NULL and a CHANGESET_DATA conflict occurs,
-** invoke the conflict handler. If it returns CHANGESET_REPLACE, set *pbRetry
-** to true before returning. In this case the caller will invoke this function
-** again, this time with pbRetry set to NULL.
-**
-** If argument pbReplace is NULL and a CHANGESET_CONFLICT conflict is 
-** encountered invoke the conflict handler with CHANGESET_CONSTRAINT instead.
-** Or, if pbReplace is not NULL, invoke it with CHANGESET_CONFLICT. If such
-** an invocation returns SQLITE_CHANGESET_REPLACE, set *pbReplace to true
-** before retrying. In this case the caller attempts to remove the conflicting
-** row before invoking this function again, this time with pbReplace set 
-** to NULL.
-**
-** If any conflict handler returns SQLITE_CHANGESET_ABORT, this function
-** returns SQLITE_ABORT. Otherwise, if no error occurs, SQLITE_OK is 
-** returned.
-*/
-static int sessionApplyOneOp(
-  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
-  SessionApplyCtx *p,             /* changeset_apply() context */
-  int(*xConflict)(void *, int, sqlite3_changeset_iter *),
-  void *pCtx,                     /* First argument for the conflict handler */
-  int *pbReplace,                 /* OUT: True to remove PK row and retry */
-  int *pbRetry                    /* OUT: True to retry. */
+static int sessionDiffFindModified(
+  sqlite3_session *pSession, 
+  SessionTable *pTab, 
+  const char *zFrom, 
+  const char *zExpr
 ){
-  const char *zDummy;
-  int op;
-  int nCol;
   int rc = SQLITE_OK;
 
-  assert( p->pDelete && p->pUpdate && p->pInsert && p->pSelect );
-  assert( p->azCol && p->abPK );
-  assert( !pbReplace || *pbReplace==0 );
+  char *zExpr2 = sessionExprCompareOther(pTab->nCol,
+      pSession->zDb, zFrom, pTab->zName, pTab->azCol, pTab->abPK
+  );
+  if( zExpr2==0 ){
+    rc = SQLITE_NOMEM;
+  }else{
+    char *zStmt = sqlite3_mprintf(
+        "SELECT * FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)",
+        pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2
+    );
+    if( zStmt==0 ){
+      rc = SQLITE_NOMEM;
+    }else{
+      sqlite3_stmt *pStmt;
+      rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0);
 
-  sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
+      if( rc==SQLITE_OK ){
+        SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx;
+        pDiffCtx->pStmt = pStmt;
+        pDiffCtx->nOldOff = pTab->nCol;
+        while( SQLITE_ROW==sqlite3_step(pStmt) ){
+          sessionPreupdateOneChange(SQLITE_UPDATE, pSession, pTab);
+        }
+        rc = sqlite3_finalize(pStmt);
+      }
+      sqlite3_free(zStmt);
+    }
+  }
 
-  if( op==SQLITE_DELETE ){
+  return rc;
+}
 
-    /* Bind values to the DELETE statement. If conflict handling is required,
-    ** bind values for all columns and set bound variable (nCol+1) to true.
-    ** Or, if conflict handling is not required, bind just the PK column
-    ** values and, if it exists, set (nCol+1) to false. Conflict handling
-    ** is not required if:
-    **
-    **   * this is a patchset, or
-    **   * (pbRetry==0), or
-    **   * all columns of the table are PK columns (in this case there is
-    **     no (nCol+1) variable to bind to).
-    */
-    u8 *abPK = (pIter->bPatchset ? p->abPK : 0);
-    rc = sessionBindRow(pIter, sqlite3changeset_old, nCol, abPK, p->pDelete);
-    if( rc==SQLITE_OK && sqlite3_bind_parameter_count(p->pDelete)>nCol ){
-      rc = sqlite3_bind_int(p->pDelete, nCol+1, (pbRetry==0 || abPK));
-    }
-    if( rc!=SQLITE_OK ) return rc;
+SQLITE_API int sqlite3session_diff(
+  sqlite3_session *pSession,
+  const char *zFrom,
+  const char *zTbl,
+  char **pzErrMsg
+){
+  const char *zDb = pSession->zDb;
+  int rc = pSession->rc;
+  SessionDiffCtx d;
 
-    sqlite3_step(p->pDelete);
-    rc = sqlite3_reset(p->pDelete);
-    if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
-      rc = sessionConflictHandler(
-          SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
-      );
-    }else if( (rc&0xff)==SQLITE_CONSTRAINT ){
-      rc = sessionConflictHandler(
-          SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0
-      );
-    }
+  memset(&d, 0, sizeof(d));
+  sessionDiffHooks(pSession, &d);
 
-  }else if( op==SQLITE_UPDATE ){
-    int i;
+  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
+  if( pzErrMsg ) *pzErrMsg = 0;
+  if( rc==SQLITE_OK ){
+    char *zExpr = 0;
+    sqlite3 *db = pSession->db;
+    SessionTable *pTo;            /* Table zTbl */
 
-    /* Bind values to the UPDATE statement. */
-    for(i=0; rc==SQLITE_OK && i<nCol; i++){
-      sqlite3_value *pOld = sessionChangesetOld(pIter, i);
-      sqlite3_value *pNew = sessionChangesetNew(pIter, i);
+    /* Locate and if necessary initialize the target table object */
+    rc = sessionFindTable(pSession, zTbl, &pTo);
+    if( pTo==0 ) goto diff_out;
+    if( sessionInitTable(pSession, pTo) ){
+      rc = pSession->rc;
+      goto diff_out;
+    }
 
-      sqlite3_bind_int(p->pUpdate, i*3+2, !!pNew);
-      if( pOld ){
-        rc = sessionBindValue(p->pUpdate, i*3+1, pOld);
+    /* Check the table schemas match */
+    if( rc==SQLITE_OK ){
+      int bHasPk = 0;
+      int bMismatch = 0;
+      int nCol;                   /* Columns in zFrom.zTbl */
+      u8 *abPK;
+      const char **azCol = 0;
+      rc = sessionTableInfo(db, zFrom, zTbl, &nCol, 0, &azCol, &abPK);
+      if( rc==SQLITE_OK ){
+        if( pTo->nCol!=nCol ){
+          bMismatch = 1;
+        }else{
+          int i;
+          for(i=0; i<nCol; i++){
+            if( pTo->abPK[i]!=abPK[i] ) bMismatch = 1;
+            if( sqlite3_stricmp(azCol[i], pTo->azCol[i]) ) bMismatch = 1;
+            if( abPK[i] ) bHasPk = 1;
+          }
+        }
       }
-      if( rc==SQLITE_OK && pNew ){
-        rc = sessionBindValue(p->pUpdate, i*3+3, pNew);
+      sqlite3_free((char*)azCol);
+      if( bMismatch ){
+        *pzErrMsg = sqlite3_mprintf("table schemas do not match");
+        rc = SQLITE_SCHEMA;
+      }
+      if( bHasPk==0 ){
+        /* Ignore tables with no primary keys */
+        goto diff_out;
       }
     }
-    if( rc==SQLITE_OK ){
-      sqlite3_bind_int(p->pUpdate, nCol*3+1, pbRetry==0 || pIter->bPatchset);
-    }
-    if( rc!=SQLITE_OK ) return rc;
-
-    /* Attempt the UPDATE. In the case of a NOTFOUND or DATA conflict,
-    ** the result will be SQLITE_OK with 0 rows modified. */
-    sqlite3_step(p->pUpdate);
-    rc = sqlite3_reset(p->pUpdate);
 
-    if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
-      /* A NOTFOUND or DATA error. Search the table to see if it contains
-      ** a row with a matching primary key. If so, this is a DATA conflict.
-      ** Otherwise, if there is no primary key match, it is a NOTFOUND. */
-
-      rc = sessionConflictHandler(
-          SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
-      );
-
-    }else if( (rc&0xff)==SQLITE_CONSTRAINT ){
-      /* This is always a CONSTRAINT conflict. */
-      rc = sessionConflictHandler(
-          SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0
+    if( rc==SQLITE_OK ){
+      zExpr = sessionExprComparePK(pTo->nCol, 
+          zDb, zFrom, pTo->zName, pTo->azCol, pTo->abPK
       );
     }
 
-  }else{
-    assert( op==SQLITE_INSERT );
-    if( p->bStat1 ){
-      /* Check if there is a conflicting row. For sqlite_stat1, this needs
-      ** to be done using a SELECT, as there is no PRIMARY KEY in the 
-      ** database schema to throw an exception if a duplicate is inserted.  */
-      rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect);
-      if( rc==SQLITE_ROW ){
-        rc = SQLITE_CONSTRAINT;
-        sqlite3_reset(p->pSelect);
-      }
+    /* Find new rows */
+    if( rc==SQLITE_OK ){
+      rc = sessionDiffFindNew(SQLITE_INSERT, pSession, pTo, zDb, zFrom, zExpr);
     }
 
+    /* Find old rows */
     if( rc==SQLITE_OK ){
-      rc = sessionBindRow(pIter, sqlite3changeset_new, nCol, 0, p->pInsert);
-      if( rc!=SQLITE_OK ) return rc;
-
-      sqlite3_step(p->pInsert);
-      rc = sqlite3_reset(p->pInsert);
+      rc = sessionDiffFindNew(SQLITE_DELETE, pSession, pTo, zFrom, zDb, zExpr);
     }
 
-    if( (rc&0xff)==SQLITE_CONSTRAINT ){
-      rc = sessionConflictHandler(
-          SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, pbReplace
-      );
+    /* Find modified rows */
+    if( rc==SQLITE_OK ){
+      rc = sessionDiffFindModified(pSession, pTo, zFrom, zExpr);
     }
+
+    sqlite3_free(zExpr);
   }
 
+ diff_out:
+  sessionPreupdateHooks(pSession);
+  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
   return rc;
 }
 
 /*
-** Attempt to apply the change that the iterator passed as the first argument
-** currently points to to the database. If a conflict is encountered, invoke
-** the conflict handler callback.
-**
-** The difference between this function and sessionApplyOne() is that this
-** function handles the case where the conflict-handler is invoked and 
-** returns SQLITE_CHANGESET_REPLACE - indicating that the change should be
-** retried in some manner.
+** Create a session object. This session object will record changes to
+** database zDb attached to connection db.
 */
-static int sessionApplyOneWithRetry(
-  sqlite3 *db,                    /* Apply change to "main" db of this handle */
-  sqlite3_changeset_iter *pIter,  /* Changeset iterator to read change from */
-  SessionApplyCtx *pApply,        /* Apply context */
-  int(*xConflict)(void*, int, sqlite3_changeset_iter*),
-  void *pCtx                      /* First argument passed to xConflict */
+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 */
 ){
-  int bReplace = 0;
-  int bRetry = 0;
-  int rc;
+  sqlite3_session *pNew;          /* Newly allocated session object */
+  sqlite3_session *pOld;          /* Session object already attached to db */
+  int nDb = sqlite3Strlen30(zDb); /* Length of zDb in bytes */
 
-  rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, &bReplace, &bRetry);
-  if( rc==SQLITE_OK ){
-    /* If the bRetry flag is set, the change has not been applied due to an
-    ** SQLITE_CHANGESET_DATA problem (i.e. this is an UPDATE or DELETE and
-    ** a row with the correct PK is present in the db, but one or more other
-    ** fields do not contain the expected values) and the conflict handler 
-    ** returned SQLITE_CHANGESET_REPLACE. In this case retry the operation,
-    ** but pass NULL as the final argument so that sessionApplyOneOp() ignores
-    ** the SQLITE_CHANGESET_DATA problem.  */
-    if( bRetry ){
-      assert( pIter->op==SQLITE_UPDATE || pIter->op==SQLITE_DELETE );
-      rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0);
-    }
+  /* Zero the output value in case an error occurs. */
+  *ppSession = 0;
 
-    /* If the bReplace flag is set, the change is an INSERT that has not
-    ** been performed because the database already contains a row with the
-    ** specified primary key and the conflict handler returned
-    ** SQLITE_CHANGESET_REPLACE. In this case remove the conflicting row
-    ** before reattempting the INSERT.  */
-    else if( bReplace ){
-      assert( pIter->op==SQLITE_INSERT );
-      rc = sqlite3_exec(db, "SAVEPOINT replace_op", 0, 0, 0);
-      if( rc==SQLITE_OK ){
-        rc = sessionBindRow(pIter, 
-            sqlite3changeset_new, pApply->nCol, pApply->abPK, pApply->pDelete);
-        sqlite3_bind_int(pApply->pDelete, pApply->nCol+1, 1);
-      }
-      if( rc==SQLITE_OK ){
-        sqlite3_step(pApply->pDelete);
-        rc = sqlite3_reset(pApply->pDelete);
-      }
-      if( rc==SQLITE_OK ){
-        rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0);
-      }
-      if( rc==SQLITE_OK ){
-        rc = sqlite3_exec(db, "RELEASE replace_op", 0, 0, 0);
-      }
-    }
-  }
+  /* Allocate and populate the new session object. */
+  pNew = (sqlite3_session *)sqlite3_malloc(sizeof(sqlite3_session) + nDb + 1);
+  if( !pNew ) return SQLITE_NOMEM;
+  memset(pNew, 0, sizeof(sqlite3_session));
+  pNew->db = db;
+  pNew->zDb = (char *)&pNew[1];
+  pNew->bEnable = 1;
+  memcpy(pNew->zDb, zDb, nDb+1);
+  sessionPreupdateHooks(pNew);
 
-  return rc;
+  /* Add the new session object to the linked list of session objects 
+  ** attached to database handle $db. Do this under the cover of the db
+  ** handle mutex.  */
+  sqlite3_mutex_enter(sqlite3_db_mutex(db));
+  pOld = (sqlite3_session*)sqlite3_preupdate_hook(db, xPreUpdate, (void*)pNew);
+  pNew->pNext = pOld;
+  sqlite3_mutex_leave(sqlite3_db_mutex(db));
+
+  *ppSession = pNew;
+  return SQLITE_OK;
 }
 
 /*
-** Retry the changes accumulated in the pApply->constraints buffer.
+** Free the list of table objects passed as the first argument. The contents
+** of the changed-rows hash tables are also deleted.
 */
-static int sessionRetryConstraints(
-  sqlite3 *db, 
-  int bPatchset,
-  const char *zTab,
-  SessionApplyCtx *pApply,
-  int(*xConflict)(void*, int, sqlite3_changeset_iter*),
-  void *pCtx                      /* First argument passed to xConflict */
-){
-  int rc = SQLITE_OK;
-
-  while( pApply->constraints.nBuf ){
-    sqlite3_changeset_iter *pIter2 = 0;
-    SessionBuffer cons = pApply->constraints;
-    memset(&pApply->constraints, 0, sizeof(SessionBuffer));
-
-    rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf);
-    if( rc==SQLITE_OK ){
-      int nByte = 2*pApply->nCol*sizeof(sqlite3_value*);
-      int rc2;
-      pIter2->bPatchset = bPatchset;
-      pIter2->zTab = (char*)zTab;
-      pIter2->nCol = pApply->nCol;
-      pIter2->abPK = pApply->abPK;
-      sessionBufferGrow(&pIter2->tblhdr, nByte, &rc);
-      pIter2->apValue = (sqlite3_value**)pIter2->tblhdr.aBuf;
-      if( rc==SQLITE_OK ) memset(pIter2->apValue, 0, nByte);
+static void sessionDeleteTable(SessionTable *pList){
+  SessionTable *pNext;
+  SessionTable *pTab;
 
-      while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter2) ){
-        rc = sessionApplyOneWithRetry(db, pIter2, pApply, xConflict, pCtx);
+  for(pTab=pList; pTab; pTab=pNext){
+    int i;
+    pNext = pTab->pNext;
+    for(i=0; i<pTab->nChange; i++){
+      SessionChange *p;
+      SessionChange *pNextChange;
+      for(p=pTab->apChange[i]; p; p=pNextChange){
+        pNextChange = p->pNext;
+        sqlite3_free(p);
       }
-
-      rc2 = sqlite3changeset_finalize(pIter2);
-      if( rc==SQLITE_OK ) rc = rc2;
     }
-    assert( pApply->bDeferConstraints || pApply->constraints.nBuf==0 );
+    sqlite3_free((char*)pTab->azCol);  /* cast works around VC++ bug */
+    sqlite3_free(pTab->apChange);
+    sqlite3_free(pTab);
+  }
+}
 
-    sqlite3_free(cons.aBuf);
-    if( rc!=SQLITE_OK ) break;
-    if( pApply->constraints.nBuf>=cons.nBuf ){
-      /* No progress was made on the last round. */
-      pApply->bDeferConstraints = 0;
+/*
+** Delete a session object previously allocated using sqlite3session_create().
+*/
+SQLITE_API void sqlite3session_delete(sqlite3_session *pSession){
+  sqlite3 *db = pSession->db;
+  sqlite3_session *pHead;
+  sqlite3_session **pp;
+
+  /* Unlink the session from the linked list of sessions attached to the
+  ** database handle. Hold the db mutex while doing so.  */
+  sqlite3_mutex_enter(sqlite3_db_mutex(db));
+  pHead = (sqlite3_session*)sqlite3_preupdate_hook(db, 0, 0);
+  for(pp=&pHead; ALWAYS((*pp)!=0); pp=&((*pp)->pNext)){
+    if( (*pp)==pSession ){
+      *pp = (*pp)->pNext;
+      if( pHead ) sqlite3_preupdate_hook(db, xPreUpdate, (void*)pHead);
+      break;
     }
   }
+  sqlite3_mutex_leave(sqlite3_db_mutex(db));
+  sqlite3ValueFree(pSession->pZeroBlob);
 
-  return rc;
+  /* Delete all attached table objects. And the contents of their 
+  ** associated hash-tables. */
+  sessionDeleteTable(pSession->pTable);
+
+  /* Free the session object itself. */
+  sqlite3_free(pSession);
 }
 
 /*
-** Argument pIter is a changeset iterator that has been initialized, but
-** not yet passed to sqlite3changeset_next(). This function applies the 
-** changeset to the main database attached to handle "db". The supplied
-** conflict handler callback is invoked to resolve any conflicts encountered
-** while applying the change.
+** Set a table filter on a Session Object.
 */
-static int sessionChangesetApply(
-  sqlite3 *db,                    /* Apply change to "main" db of this handle */
-  sqlite3_changeset_iter *pIter,  /* Changeset to apply */
-  int(*xFilter)(
-    void *pCtx,                   /* Copy of sixth arg to _apply() */
-    const char *zTab              /* Table name */
-  ),
-  int(*xConflict)(
-    void *pCtx,                   /* Copy of fifth 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 */
-  void **ppRebase, int *pnRebase, /* OUT: Rebase information */
-  int flags                       /* SESSION_APPLY_XXX flags */
+SQLITE_API void sqlite3session_table_filter(
+  sqlite3_session *pSession, 
+  int(*xFilter)(void*, const char*),
+  void *pCtx                      /* First argument passed to xFilter */
 ){
-  int schemaMismatch = 0;
-  int rc = SQLITE_OK;             /* Return code */
-  const char *zTab = 0;           /* Name of current table */
-  int nTab = 0;                   /* Result of sqlite3Strlen30(zTab) */
-  SessionApplyCtx sApply;         /* changeset_apply() context object */
-  int bPatchset;
-
-  assert( xConflict!=0 );
-
-  pIter->in.bNoDiscard = 1;
-  memset(&sApply, 0, sizeof(sApply));
-  sqlite3_mutex_enter(sqlite3_db_mutex(db));
-  if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
-    rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
-  }
-  if( rc==SQLITE_OK ){
-    rc = sqlite3_exec(db, "PRAGMA defer_foreign_keys = 1", 0, 0, 0);
-  }
-  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter) ){
-    int nCol;
-    int op;
-    const char *zNew;
-    
-    sqlite3changeset_op(pIter, &zNew, &nCol, &op, 0);
+  pSession->bAutoAttach = 1;
+  pSession->pFilterCtx = pCtx;
+  pSession->xTableFilter = xFilter;
+}
 
-    if( zTab==0 || sqlite3_strnicmp(zNew, zTab, nTab+1) ){
-      u8 *abPK;
+/*
+** Attach a table to a session. All subsequent changes made to the table
+** while the session object is enabled will be recorded.
+**
+** Only tables that have a PRIMARY KEY defined may be attached. It does
+** not matter if the PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias)
+** or not.
+*/
+SQLITE_API int sqlite3session_attach(
+  sqlite3_session *pSession,      /* Session object */
+  const char *zName               /* Table name */
+){
+  int rc = SQLITE_OK;
+  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
 
-      rc = sessionRetryConstraints(
-          db, pIter->bPatchset, zTab, &sApply, xConflict, pCtx
-      );
-      if( rc!=SQLITE_OK ) break;
+  if( !zName ){
+    pSession->bAutoAttach = 1;
+  }else{
+    SessionTable *pTab;           /* New table object (if required) */
+    int nName;                    /* Number of bytes in string zName */
 
-      sqlite3_free((char*)sApply.azCol);  /* cast works around VC++ bug */
-      sqlite3_finalize(sApply.pDelete);
-      sqlite3_finalize(sApply.pUpdate); 
-      sqlite3_finalize(sApply.pInsert);
-      sqlite3_finalize(sApply.pSelect);
-      sApply.db = db;
-      sApply.pDelete = 0;
-      sApply.pUpdate = 0;
-      sApply.pInsert = 0;
-      sApply.pSelect = 0;
-      sApply.nCol = 0;
-      sApply.azCol = 0;
-      sApply.abPK = 0;
-      sApply.bStat1 = 0;
-      sApply.bDeferConstraints = 1;
-      sApply.bRebaseStarted = 0;
-      memset(&sApply.constraints, 0, sizeof(SessionBuffer));
+    /* First search for an existing entry. If one is found, this call is
+    ** a no-op. Return early. */
+    nName = sqlite3Strlen30(zName);
+    for(pTab=pSession->pTable; pTab; pTab=pTab->pNext){
+      if( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ) break;
+    }
 
-      /* If an xFilter() callback was specified, invoke it now. If the 
-      ** xFilter callback returns zero, skip this table. If it returns
-      ** non-zero, proceed. */
-      schemaMismatch = (xFilter && (0==xFilter(pCtx, zNew)));
-      if( schemaMismatch ){
-        zTab = sqlite3_mprintf("%s", zNew);
-        if( zTab==0 ){
-          rc = SQLITE_NOMEM;
-          break;
-        }
-        nTab = (int)strlen(zTab);
-        sApply.azCol = (const char **)zTab;
+    if( !pTab ){
+      /* Allocate new SessionTable object. */
+      pTab = (SessionTable *)sqlite3_malloc(sizeof(SessionTable) + nName + 1);
+      if( !pTab ){
+        rc = SQLITE_NOMEM;
       }else{
-        int nMinCol = 0;
-        int i;
-
-        sqlite3changeset_pk(pIter, &abPK, 0);
-        rc = sessionTableInfo(
-            db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK
-        );
-        if( rc!=SQLITE_OK ) break;
-        for(i=0; i<sApply.nCol; i++){
-          if( sApply.abPK[i] ) nMinCol = i+1;
-        }
-  
-        if( sApply.nCol==0 ){
-          schemaMismatch = 1;
-          sqlite3_log(SQLITE_SCHEMA, 
-              "sqlite3changeset_apply(): no such table: %s", zTab
-          );
-        }
-        else if( sApply.nCol<nCol ){
-          schemaMismatch = 1;
-          sqlite3_log(SQLITE_SCHEMA, 
-              "sqlite3changeset_apply(): table %s has %d columns, "
-              "expected %d or more", 
-              zTab, sApply.nCol, nCol
-          );
-        }
-        else if( nCol<nMinCol || memcmp(sApply.abPK, abPK, nCol)!=0 ){
-          schemaMismatch = 1;
-          sqlite3_log(SQLITE_SCHEMA, "sqlite3changeset_apply(): "
-              "primary key mismatch for table %s", zTab
-          );
-        }
-        else{
-          sApply.nCol = nCol;
-          if( 0==sqlite3_stricmp(zTab, "sqlite_stat1") ){
-            if( (rc = sessionStat1Sql(db, &sApply) ) ){
-              break;
-            }
-            sApply.bStat1 = 1;
-          }else{
-            if((rc = sessionSelectRow(db, zTab, &sApply))
-                || (rc = sessionUpdateRow(db, zTab, &sApply))
-                || (rc = sessionDeleteRow(db, zTab, &sApply))
-                || (rc = sessionInsertRow(db, zTab, &sApply))
-              ){
-              break;
-            }
-            sApply.bStat1 = 0;
-          }
-        }
-        nTab = sqlite3Strlen30(zTab);
+        /* Populate the new SessionTable object and link it into the list.
+        ** The new object must be linked onto the end of the list, not 
+        ** simply added to the start of it in order to ensure that tables
+        ** appear in the correct order when a changeset or patchset is
+        ** eventually generated. */
+        SessionTable **ppTab;
+        memset(pTab, 0, sizeof(SessionTable));
+        pTab->zName = (char *)&pTab[1];
+        memcpy(pTab->zName, zName, nName+1);
+        for(ppTab=&pSession->pTable; *ppTab; ppTab=&(*ppTab)->pNext);
+        *ppTab = pTab;
       }
     }
-
-    /* If there is a schema mismatch on the current table, proceed to the
-    ** next change. A log message has already been issued. */
-    if( schemaMismatch ) continue;
-
-    rc = sessionApplyOneWithRetry(db, pIter, &sApply, xConflict, pCtx);
   }
 
-  bPatchset = pIter->bPatchset;
-  if( rc==SQLITE_OK ){
-    rc = sqlite3changeset_finalize(pIter);
-  }else{
-    sqlite3changeset_finalize(pIter);
-  }
+  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
+  return rc;
+}
 
-  if( rc==SQLITE_OK ){
-    rc = sessionRetryConstraints(db, bPatchset, zTab, &sApply, xConflict, pCtx);
-  }
+/*
+** Ensure that there is room in the buffer to append nByte bytes of data.
+** If not, use sqlite3_realloc() to grow the buffer so that there is.
+**
+** If successful, return zero. Otherwise, if an OOM condition is encountered,
+** set *pRc to SQLITE_NOMEM and return non-zero.
+*/
+static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){
+  if( *pRc==SQLITE_OK && p->nAlloc-p->nBuf<nByte ){
+    u8 *aNew;
+    int nNew = p->nAlloc ? p->nAlloc : 128;
+    do {
+      nNew = nNew*2;
+    }while( nNew<(p->nBuf+nByte) );
 
-  if( rc==SQLITE_OK ){
-    int nFk, notUsed;
-    sqlite3_db_status(db, SQLITE_DBSTATUS_DEFERRED_FKS, &nFk, &notUsed, 0);
-    if( nFk!=0 ){
-      int res = SQLITE_CHANGESET_ABORT;
-      sqlite3_changeset_iter sIter;
-      memset(&sIter, 0, sizeof(sIter));
-      sIter.nCol = nFk;
-      res = xConflict(pCtx, SQLITE_CHANGESET_FOREIGN_KEY, &sIter);
-      if( res!=SQLITE_CHANGESET_OMIT ){
-        rc = SQLITE_CONSTRAINT;
-      }
+    aNew = (u8 *)sqlite3_realloc(p->aBuf, nNew);
+    if( 0==aNew ){
+      *pRc = SQLITE_NOMEM;
+    }else{
+      p->aBuf = aNew;
+      p->nAlloc = nNew;
     }
   }
-  sqlite3_exec(db, "PRAGMA defer_foreign_keys = 0", 0, 0, 0);
+  return (*pRc!=SQLITE_OK);
+}
 
-  if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
+/*
+** Append the value passed as the second argument to the buffer passed
+** as the first.
+**
+** This function is a no-op if *pRc is non-zero when it is called.
+** Otherwise, if an error occurs, *pRc is set to an SQLite error code
+** before returning.
+*/
+static void sessionAppendValue(SessionBuffer *p, sqlite3_value *pVal, int *pRc){
+  int rc = *pRc;
+  if( rc==SQLITE_OK ){
+    int nByte = 0;
+    rc = sessionSerializeValue(0, pVal, &nByte);
+    sessionBufferGrow(p, nByte, &rc);
     if( rc==SQLITE_OK ){
-      rc = sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
+      rc = sessionSerializeValue(&p->aBuf[p->nBuf], pVal, 0);
+      p->nBuf += nByte;
     }else{
-      sqlite3_exec(db, "ROLLBACK TO changeset_apply", 0, 0, 0);
-      sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
+      *pRc = rc;
     }
   }
+}
 
-  if( rc==SQLITE_OK && bPatchset==0 && ppRebase && pnRebase ){
-    *ppRebase = (void*)sApply.rebase.aBuf;
-    *pnRebase = sApply.rebase.nBuf;
-    sApply.rebase.aBuf = 0;
+/*
+** This function is a no-op if *pRc is other than SQLITE_OK when it is 
+** called. Otherwise, append a single byte to the buffer. 
+**
+** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
+** returning.
+*/
+static void sessionAppendByte(SessionBuffer *p, u8 v, int *pRc){
+  if( 0==sessionBufferGrow(p, 1, pRc) ){
+    p->aBuf[p->nBuf++] = v;
   }
-  sqlite3_finalize(sApply.pInsert);
-  sqlite3_finalize(sApply.pDelete);
-  sqlite3_finalize(sApply.pUpdate);
-  sqlite3_finalize(sApply.pSelect);
-  sqlite3_free((char*)sApply.azCol);  /* cast works around VC++ bug */
-  sqlite3_free((char*)sApply.constraints.aBuf);
-  sqlite3_free((char*)sApply.rebase.aBuf);
-  sqlite3_mutex_leave(sqlite3_db_mutex(db));
-  return rc;
 }
 
 /*
-** Apply the changeset passed via pChangeset/nChangeset to the main 
-** database attached to handle "db".
+** This function is a no-op if *pRc is other than SQLITE_OK when it is 
+** called. Otherwise, append a single varint to the buffer. 
+**
+** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
+** returning.
 */
-SQLITE_API int sqlite3changeset_apply_v2(
-  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 */
-  void **ppRebase, int *pnRebase,
-  int flags
-){
-  sqlite3_changeset_iter *pIter;  /* Iterator to skip through changeset */  
-  int rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
-  if( rc==SQLITE_OK ){
-    rc = sessionChangesetApply(
-        db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
-    );
+static void sessionAppendVarint(SessionBuffer *p, int v, int *pRc){
+  if( 0==sessionBufferGrow(p, 9, pRc) ){
+    p->nBuf += sessionVarintPut(&p->aBuf[p->nBuf], v);
   }
-  return rc;
 }
 
 /*
-** Apply the changeset passed via pChangeset/nChangeset to the main database
-** attached to handle "db". Invoke the supplied conflict handler callback
-** to resolve any conflicts encountered while applying the change.
+** This function is a no-op if *pRc is other than SQLITE_OK when it is 
+** called. Otherwise, append a blob of data to the buffer. 
+**
+** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
+** returning.
 */
-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 fifth 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 */
+static void sessionAppendBlob(
+  SessionBuffer *p, 
+  const u8 *aBlob, 
+  int nBlob, 
+  int *pRc
 ){
-  return sqlite3changeset_apply_v2(
-      db, nChangeset, pChangeset, xFilter, xConflict, pCtx, 0, 0, 0
-  );
+  if( nBlob>0 && 0==sessionBufferGrow(p, nBlob, pRc) ){
+    memcpy(&p->aBuf[p->nBuf], aBlob, nBlob);
+    p->nBuf += nBlob;
+  }
 }
 
 /*
-** Apply the changeset passed via xInput/pIn to the main database
-** attached to handle "db". Invoke the supplied conflict handler callback
-** to resolve any conflicts encountered while applying the change.
+** This function is a no-op if *pRc is other than SQLITE_OK when it is 
+** called. Otherwise, append a string to the buffer. All bytes in the string
+** up to (but not including) the nul-terminator are written to the buffer.
+**
+** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
+** returning.
 */
-SQLITE_API int sqlite3changeset_apply_v2_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 */
-  void **ppRebase, int *pnRebase,
-  int flags
+static void sessionAppendStr(
+  SessionBuffer *p, 
+  const char *zStr, 
+  int *pRc
 ){
-  sqlite3_changeset_iter *pIter;  /* Iterator to skip through changeset */  
-  int rc = sqlite3changeset_start_strm(&pIter, xInput, pIn);
-  if( rc==SQLITE_OK ){
-    rc = sessionChangesetApply(
-        db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
-    );
+  int nStr = sqlite3Strlen30(zStr);
+  if( 0==sessionBufferGrow(p, nStr, pRc) ){
+    memcpy(&p->aBuf[p->nBuf], zStr, nStr);
+    p->nBuf += nStr;
   }
-  return rc;
 }
-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 */
+
+/*
+** This function is a no-op if *pRc is other than SQLITE_OK when it is 
+** called. Otherwise, append the string representation of integer iVal
+** to the buffer. No nul-terminator is written.
+**
+** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
+** returning.
+*/
+static void sessionAppendInteger(
+  SessionBuffer *p,               /* Buffer to append to */
+  int iVal,                       /* Value to write the string rep. of */
+  int *pRc                        /* IN/OUT: Error code */
 ){
-  return sqlite3changeset_apply_v2_strm(
-      db, xInput, pIn, xFilter, xConflict, pCtx, 0, 0, 0
-  );
+  char aBuf[24];
+  sqlite3_snprintf(sizeof(aBuf)-1, aBuf, "%d", iVal);
+  sessionAppendStr(p, aBuf, pRc);
 }
 
 /*
-** sqlite3_changegroup handle.
+** This function is a no-op if *pRc is other than SQLITE_OK when it is 
+** called. Otherwise, append the string zStr enclosed in quotes (") and
+** with any embedded quote characters escaped to the buffer. No 
+** nul-terminator byte is written.
+**
+** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
+** returning.
 */
-struct sqlite3_changegroup {
-  int rc;                         /* Error code */
-  int bPatch;                     /* True to accumulate patchsets */
-  SessionTable *pList;            /* List of tables in current patch */
-};
+static void sessionAppendIdent(
+  SessionBuffer *p,               /* Buffer to a append to */
+  const char *zStr,               /* String to quote, escape and append */
+  int *pRc                        /* IN/OUT: Error code */
+){
+  int nStr = sqlite3Strlen30(zStr)*2 + 2 + 1;
+  if( 0==sessionBufferGrow(p, nStr, pRc) ){
+    char *zOut = (char *)&p->aBuf[p->nBuf];
+    const char *zIn = zStr;
+    *zOut++ = '"';
+    while( *zIn ){
+      if( *zIn=='"' ) *zOut++ = '"';
+      *zOut++ = *(zIn++);
+    }
+    *zOut++ = '"';
+    p->nBuf = (int)((u8 *)zOut - p->aBuf);
+  }
+}
 
 /*
-** This function is called to merge two changes to the same row together as
-** part of an sqlite3changeset_concat() operation. A new change object is
-** allocated and a pointer to it stored in *ppNew.
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
+** called. Otherwse, it appends the serialized version of the value stored
+** in column iCol of the row that SQL statement pStmt currently points
+** to to the buffer.
 */
-static int sessionChangeMerge(
-  SessionTable *pTab,             /* Table structure */
-  int bRebase,                    /* True for a rebase hash-table */
-  int bPatchset,                  /* True for patchsets */
-  SessionChange *pExist,          /* Existing change */
-  int op2,                        /* Second change operation */
-  int bIndirect,                  /* True if second change is indirect */
-  u8 *aRec,                       /* Second change record */
-  int nRec,                       /* Number of bytes in aRec */
-  SessionChange **ppNew           /* OUT: Merged change */
+static void sessionAppendCol(
+  SessionBuffer *p,               /* Buffer to append to */
+  sqlite3_stmt *pStmt,            /* Handle pointing to row containing value */
+  int iCol,                       /* Column to read value from */
+  int *pRc                        /* IN/OUT: Error code */
 ){
-  SessionChange *pNew = 0;
-  int rc = SQLITE_OK;
-
-  if( !pExist ){
-    pNew = (SessionChange *)sqlite3_malloc(sizeof(SessionChange) + nRec);
-    if( !pNew ){
-      return SQLITE_NOMEM;
-    }
-    memset(pNew, 0, sizeof(SessionChange));
-    pNew->op = op2;
-    pNew->bIndirect = bIndirect;
-    pNew->aRecord = (u8*)&pNew[1];
-    if( bIndirect==0 || bRebase==0 ){
-      pNew->nRecord = nRec;
-      memcpy(pNew->aRecord, aRec, nRec);
-    }else{
-      int i;
-      u8 *pIn = aRec;
-      u8 *pOut = pNew->aRecord;
-      for(i=0; i<pTab->nCol; i++){
-        int nIn = sessionSerialLen(pIn);
-        if( *pIn==0 ){
-          *pOut++ = 0;
-        }else if( pTab->abPK[i]==0 ){
-          *pOut++ = 0xFF;
-        }else{
-          memcpy(pOut, pIn, nIn);
-          pOut += nIn;
-        }
-        pIn += nIn;
+  if( *pRc==SQLITE_OK ){
+    int eType = sqlite3_column_type(pStmt, iCol);
+    sessionAppendByte(p, (u8)eType, pRc);
+    if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+      sqlite3_int64 i;
+      u8 aBuf[8];
+      if( eType==SQLITE_INTEGER ){
+        i = sqlite3_column_int64(pStmt, iCol);
+      }else{
+        double r = sqlite3_column_double(pStmt, iCol);
+        memcpy(&i, &r, 8);
       }
-      pNew->nRecord = pOut - pNew->aRecord;
+      sessionPutI64(aBuf, i);
+      sessionAppendBlob(p, aBuf, 8, pRc);
     }
-  }else if( bRebase ){
-    if( pExist->op==SQLITE_DELETE && pExist->bIndirect ){
-      *ppNew = pExist;
-    }else{
-      int nByte = nRec + pExist->nRecord + sizeof(SessionChange);
-      pNew = (SessionChange*)sqlite3_malloc(nByte);
-      if( pNew==0 ){
-        rc = SQLITE_NOMEM;
+    if( eType==SQLITE_BLOB || eType==SQLITE_TEXT ){
+      u8 *z;
+      int nByte;
+      if( eType==SQLITE_BLOB ){
+        z = (u8 *)sqlite3_column_blob(pStmt, iCol);
       }else{
-        int i;
-        u8 *a1 = pExist->aRecord;
-        u8 *a2 = aRec;
-        u8 *pOut;
+        z = (u8 *)sqlite3_column_text(pStmt, iCol);
+      }
+      nByte = sqlite3_column_bytes(pStmt, iCol);
+      if( z || (eType==SQLITE_BLOB && nByte==0) ){
+        sessionAppendVarint(p, nByte, pRc);
+        sessionAppendBlob(p, z, nByte, pRc);
+      }else{
+        *pRc = SQLITE_NOMEM;
+      }
+    }
+  }
+}
 
-        memset(pNew, 0, nByte);
-        pNew->bIndirect = bIndirect || pExist->bIndirect;
-        pNew->op = op2;
-        pOut = pNew->aRecord = (u8*)&pNew[1];
+/*
+**
+** This function appends an update change to the buffer (see the comments 
+** under "CHANGESET FORMAT" at the top of the file). An update change 
+** consists of:
+**
+**   1 byte:  SQLITE_UPDATE (0x17)
+**   n bytes: old.* record (see RECORD FORMAT)
+**   m bytes: new.* record (see RECORD FORMAT)
+**
+** The SessionChange object passed as the third argument contains the
+** values that were stored in the row when the session began (the old.*
+** values). The statement handle passed as the second argument points
+** at the current version of the row (the new.* values).
+**
+** If all of the old.* values are equal to their corresponding new.* value
+** (i.e. nothing has changed), then no data at all is appended to the buffer.
+**
+** Otherwise, the old.* record contains all primary key values and the 
+** original values of any fields that have been modified. The new.* record 
+** contains the new values of only those fields that have been modified.
+*/ 
+static int sessionAppendUpdate(
+  SessionBuffer *pBuf,            /* Buffer to append to */
+  int bPatchset,                  /* True for "patchset", 0 for "changeset" */
+  sqlite3_stmt *pStmt,            /* Statement handle pointing at new row */
+  SessionChange *p,               /* Object containing old values */
+  u8 *abPK                        /* Boolean array - true for PK columns */
+){
+  int rc = SQLITE_OK;
+  SessionBuffer buf2 = {0,0,0}; /* Buffer to accumulate new.* record in */
+  int bNoop = 1;                /* Set to zero if any values are modified */
+  int nRewind = pBuf->nBuf;     /* Set to zero if any values are modified */
+  int i;                        /* Used to iterate through columns */
+  u8 *pCsr = p->aRecord;        /* Used to iterate through old.* values */
 
-        for(i=0; i<pTab->nCol; i++){
-          int n1 = sessionSerialLen(a1);
-          int n2 = sessionSerialLen(a2);
-          if( *a1==0xFF || (pTab->abPK[i]==0 && bIndirect) ){
-            *pOut++ = 0xFF;
-          }else if( *a2==0 ){
-            memcpy(pOut, a1, n1);
-            pOut += n1;
+  sessionAppendByte(pBuf, SQLITE_UPDATE, &rc);
+  sessionAppendByte(pBuf, p->bIndirect, &rc);
+  for(i=0; i<sqlite3_column_count(pStmt); i++){
+    int bChanged = 0;
+    int nAdvance;
+    int eType = *pCsr;
+    switch( eType ){
+      case SQLITE_NULL:
+        nAdvance = 1;
+        if( sqlite3_column_type(pStmt, i)!=SQLITE_NULL ){
+          bChanged = 1;
+        }
+        break;
+
+      case SQLITE_FLOAT:
+      case SQLITE_INTEGER: {
+        nAdvance = 9;
+        if( eType==sqlite3_column_type(pStmt, i) ){
+          sqlite3_int64 iVal = sessionGetI64(&pCsr[1]);
+          if( eType==SQLITE_INTEGER ){
+            if( iVal==sqlite3_column_int64(pStmt, i) ) break;
           }else{
-            memcpy(pOut, a2, n2);
-            pOut += n2;
+            double dVal;
+            memcpy(&dVal, &iVal, 8);
+            if( dVal==sqlite3_column_double(pStmt, i) ) break;
           }
-          a1 += n1;
-          a2 += n2;
         }
-        pNew->nRecord = pOut - pNew->aRecord;
+        bChanged = 1;
+        break;
+      }
+
+      default: {
+        int n;
+        int nHdr = 1 + sessionVarintGet(&pCsr[1], &n);
+        assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
+        nAdvance = nHdr + n;
+        if( eType==sqlite3_column_type(pStmt, i) 
+         && n==sqlite3_column_bytes(pStmt, i) 
+         && (n==0 || 0==memcmp(&pCsr[nHdr], sqlite3_column_blob(pStmt, i), n))
+        ){
+          break;
+        }
+        bChanged = 1;
       }
-      sqlite3_free(pExist);
     }
-  }else{
-    int op1 = pExist->op;
 
-    /* 
-    **   op1=INSERT, op2=INSERT      ->      Unsupported. Discard op2.
-    **   op1=INSERT, op2=UPDATE      ->      INSERT.
-    **   op1=INSERT, op2=DELETE      ->      (none)
-    **
-    **   op1=UPDATE, op2=INSERT      ->      Unsupported. Discard op2.
-    **   op1=UPDATE, op2=UPDATE      ->      UPDATE.
-    **   op1=UPDATE, op2=DELETE      ->      DELETE.
-    **
-    **   op1=DELETE, op2=INSERT      ->      UPDATE.
-    **   op1=DELETE, op2=UPDATE      ->      Unsupported. Discard op2.
-    **   op1=DELETE, op2=DELETE      ->      Unsupported. Discard op2.
-    */   
-    if( (op1==SQLITE_INSERT && op2==SQLITE_INSERT)
-     || (op1==SQLITE_UPDATE && op2==SQLITE_INSERT)
-     || (op1==SQLITE_DELETE && op2==SQLITE_UPDATE)
-     || (op1==SQLITE_DELETE && op2==SQLITE_DELETE)
-    ){
-      pNew = pExist;
-    }else if( op1==SQLITE_INSERT && op2==SQLITE_DELETE ){
-      sqlite3_free(pExist);
-      assert( pNew==0 );
-    }else{
-      u8 *aExist = pExist->aRecord;
-      int nByte;
-      u8 *aCsr;
+    /* If at least one field has been modified, this is not a no-op. */
+    if( bChanged ) bNoop = 0;
 
-      /* Allocate a new SessionChange object. Ensure that the aRecord[]
-      ** buffer of the new object is large enough to hold any record that
-      ** may be generated by combining the input records.  */
-      nByte = sizeof(SessionChange) + pExist->nRecord + nRec;
-      pNew = (SessionChange *)sqlite3_malloc(nByte);
-      if( !pNew ){
-        sqlite3_free(pExist);
-        return SQLITE_NOMEM;
+    /* Add a field to the old.* record. This is omitted if this modules is
+    ** currently generating a patchset. */
+    if( bPatchset==0 ){
+      if( bChanged || abPK[i] ){
+        sessionAppendBlob(pBuf, pCsr, nAdvance, &rc);
+      }else{
+        sessionAppendByte(pBuf, 0, &rc);
       }
-      memset(pNew, 0, sizeof(SessionChange));
-      pNew->bIndirect = (bIndirect && pExist->bIndirect);
-      aCsr = pNew->aRecord = (u8 *)&pNew[1];
+    }
 
-      if( op1==SQLITE_INSERT ){             /* INSERT + UPDATE */
-        u8 *a1 = aRec;
-        assert( op2==SQLITE_UPDATE );
-        pNew->op = SQLITE_INSERT;
-        if( bPatchset==0 ) sessionSkipRecord(&a1, pTab->nCol);
-        sessionMergeRecord(&aCsr, pTab->nCol, aExist, a1);
-      }else if( op1==SQLITE_DELETE ){       /* DELETE + INSERT */
-        assert( op2==SQLITE_INSERT );
-        pNew->op = SQLITE_UPDATE;
-        if( bPatchset ){
-          memcpy(aCsr, aRec, nRec);
-          aCsr += nRec;
-        }else{
-          if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aExist, 0,aRec,0) ){
-            sqlite3_free(pNew);
-            pNew = 0;
-          }
-        }
-      }else if( op2==SQLITE_UPDATE ){       /* UPDATE + UPDATE */
-        u8 *a1 = aExist;
-        u8 *a2 = aRec;
-        assert( op1==SQLITE_UPDATE );
-        if( bPatchset==0 ){
-          sessionSkipRecord(&a1, pTab->nCol);
-          sessionSkipRecord(&a2, pTab->nCol);
-        }
-        pNew->op = SQLITE_UPDATE;
-        if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aRec, aExist,a1,a2) ){
-          sqlite3_free(pNew);
-          pNew = 0;
-        }
-      }else{                                /* UPDATE + DELETE */
-        assert( op1==SQLITE_UPDATE && op2==SQLITE_DELETE );
-        pNew->op = SQLITE_DELETE;
-        if( bPatchset ){
-          memcpy(aCsr, aRec, nRec);
-          aCsr += nRec;
-        }else{
-          sessionMergeRecord(&aCsr, pTab->nCol, aRec, aExist);
+    /* Add a field to the new.* record. Or the only record if currently
+    ** generating a patchset.  */
+    if( bChanged || (bPatchset && abPK[i]) ){
+      sessionAppendCol(&buf2, pStmt, i, &rc);
+    }else{
+      sessionAppendByte(&buf2, 0, &rc);
+    }
+
+    pCsr += nAdvance;
+  }
+
+  if( bNoop ){
+    pBuf->nBuf = nRewind;
+  }else{
+    sessionAppendBlob(pBuf, buf2.aBuf, buf2.nBuf, &rc);
+  }
+  sqlite3_free(buf2.aBuf);
+
+  return rc;
+}
+
+/*
+** Append a DELETE change to the buffer passed as the first argument. Use
+** the changeset format if argument bPatchset is zero, or the patchset
+** format otherwise.
+*/
+static int sessionAppendDelete(
+  SessionBuffer *pBuf,            /* Buffer to append to */
+  int bPatchset,                  /* True for "patchset", 0 for "changeset" */
+  SessionChange *p,               /* Object containing old values */
+  int nCol,                       /* Number of columns in table */
+  u8 *abPK                        /* Boolean array - true for PK columns */
+){
+  int rc = SQLITE_OK;
+
+  sessionAppendByte(pBuf, SQLITE_DELETE, &rc);
+  sessionAppendByte(pBuf, p->bIndirect, &rc);
+
+  if( bPatchset==0 ){
+    sessionAppendBlob(pBuf, p->aRecord, p->nRecord, &rc);
+  }else{
+    int i;
+    u8 *a = p->aRecord;
+    for(i=0; i<nCol; i++){
+      u8 *pStart = a;
+      int eType = *a++;
+
+      switch( eType ){
+        case 0:
+        case SQLITE_NULL:
+          assert( abPK[i]==0 );
+          break;
+
+        case SQLITE_FLOAT:
+        case SQLITE_INTEGER:
+          a += 8;
+          break;
+
+        default: {
+          int n;
+          a += sessionVarintGet(a, &n);
+          a += n;
+          break;
         }
       }
-
-      if( pNew ){
-        pNew->nRecord = (int)(aCsr - pNew->aRecord);
+      if( abPK[i] ){
+        sessionAppendBlob(pBuf, pStart, (int)(a-pStart), &rc);
       }
-      sqlite3_free(pExist);
     }
+    assert( (a - p->aRecord)==p->nRecord );
   }
 
-  *ppNew = pNew;
   return rc;
 }
 
 /*
-** Add all changes in the changeset traversed by the iterator passed as
-** the first argument to the changegroup hash tables.
+** Formulate and prepare a SELECT statement to retrieve a row from table
+** zTab in database zDb based on its primary key. i.e.
+**
+**   SELECT * FROM zDb.zTab WHERE pk1 = ? AND pk2 = ? AND ...
 */
-static int sessionChangesetToHash(
-  sqlite3_changeset_iter *pIter,   /* Iterator to read from */
-  sqlite3_changegroup *pGrp,       /* Changegroup object to add changeset to */
-  int bRebase                      /* True if hash table is for rebasing */
+static int sessionSelectStmt(
+  sqlite3 *db,                    /* Database handle */
+  const char *zDb,                /* Database name */
+  const char *zTab,               /* Table name */
+  int nCol,                       /* Number of columns in table */
+  const char **azCol,             /* Names of table columns */
+  u8 *abPK,                       /* PRIMARY KEY  array */
+  sqlite3_stmt **ppStmt           /* OUT: Prepared SELECT statement */
 ){
-  u8 *aRec;
-  int nRec;
   int rc = SQLITE_OK;
-  SessionTable *pTab = 0;
+  char *zSql = 0;
+  int nSql = -1;
 
-  while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec, 0) ){
-    const char *zNew;
-    int nCol;
-    int op;
-    int iHash;
-    int bIndirect;
-    SessionChange *pChange;
-    SessionChange *pExist = 0;
-    SessionChange **pp;
+  if( 0==sqlite3_stricmp("sqlite_stat1", zTab) ){
+    zSql = sqlite3_mprintf(
+        "SELECT tbl, ?2, stat FROM %Q.sqlite_stat1 WHERE tbl IS ?1 AND "
+        "idx IS (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", zDb
+    );
+    if( zSql==0 ) rc = SQLITE_NOMEM;
+  }else{
+    int i;
+    const char *zSep = "";
+    SessionBuffer buf = {0, 0, 0};
 
-    if( pGrp->pList==0 ){
-      pGrp->bPatch = pIter->bPatchset;
-    }else if( pIter->bPatchset!=pGrp->bPatch ){
-      rc = SQLITE_ERROR;
-      break;
+    sessionAppendStr(&buf, "SELECT * FROM ", &rc);
+    sessionAppendIdent(&buf, zDb, &rc);
+    sessionAppendStr(&buf, ".", &rc);
+    sessionAppendIdent(&buf, zTab, &rc);
+    sessionAppendStr(&buf, " WHERE ", &rc);
+    for(i=0; i<nCol; i++){
+      if( abPK[i] ){
+        sessionAppendStr(&buf, zSep, &rc);
+        sessionAppendIdent(&buf, azCol[i], &rc);
+        sessionAppendStr(&buf, " IS ?", &rc);
+        sessionAppendInteger(&buf, i+1, &rc);
+        zSep = " AND ";
+      }
     }
+    zSql = (char*)buf.aBuf;
+    nSql = buf.nBuf;
+  }
 
-    sqlite3changeset_op(pIter, &zNew, &nCol, &op, &bIndirect);
-    if( !pTab || sqlite3_stricmp(zNew, pTab->zName) ){
-      /* Search the list for a matching table */
-      int nNew = (int)strlen(zNew);
-      u8 *abPK;
+  if( rc==SQLITE_OK ){
+    rc = sqlite3_prepare_v2(db, zSql, nSql, ppStmt, 0);
+  }
+  sqlite3_free(zSql);
+  return rc;
+}
 
-      sqlite3changeset_pk(pIter, &abPK, 0);
-      for(pTab = pGrp->pList; pTab; pTab=pTab->pNext){
-        if( 0==sqlite3_strnicmp(pTab->zName, zNew, nNew+1) ) break;
-      }
-      if( !pTab ){
-        SessionTable **ppTab;
+/*
+** Bind the PRIMARY KEY values from the change passed in argument pChange
+** to the SELECT statement passed as the first argument. The SELECT statement
+** is as prepared by function sessionSelectStmt().
+**
+** Return SQLITE_OK if all PK values are successfully bound, or an SQLite
+** error code (e.g. SQLITE_NOMEM) otherwise.
+*/
+static int sessionSelectBind(
+  sqlite3_stmt *pSelect,          /* SELECT from sessionSelectStmt() */
+  int nCol,                       /* Number of columns in table */
+  u8 *abPK,                       /* PRIMARY KEY array */
+  SessionChange *pChange          /* Change structure */
+){
+  int i;
+  int rc = SQLITE_OK;
+  u8 *a = pChange->aRecord;
 
-        pTab = sqlite3_malloc(sizeof(SessionTable) + nCol + nNew+1);
-        if( !pTab ){
-          rc = SQLITE_NOMEM;
-          break;
-        }
-        memset(pTab, 0, sizeof(SessionTable));
-        pTab->nCol = nCol;
-        pTab->abPK = (u8*)&pTab[1];
-        memcpy(pTab->abPK, abPK, nCol);
-        pTab->zName = (char*)&pTab->abPK[nCol];
-        memcpy(pTab->zName, zNew, nNew+1);
+  for(i=0; i<nCol && rc==SQLITE_OK; i++){
+    int eType = *a++;
 
-        /* The new object must be linked on to the end of the list, not
-        ** simply added to the start of it. This is to ensure that the
-        ** tables within the output of sqlite3changegroup_output() are in 
-        ** the right order.  */
-        for(ppTab=&pGrp->pList; *ppTab; ppTab=&(*ppTab)->pNext);
-        *ppTab = pTab;
-      }else if( pTab->nCol!=nCol || memcmp(pTab->abPK, abPK, nCol) ){
-        rc = SQLITE_SCHEMA;
+    switch( eType ){
+      case 0:
+      case SQLITE_NULL:
+        assert( abPK[i]==0 );
         break;
-      }
-    }
 
-    if( sessionGrowHash(pIter->bPatchset, pTab) ){
-      rc = SQLITE_NOMEM;
-      break;
-    }
-    iHash = sessionChangeHash(
-        pTab, (pIter->bPatchset && op==SQLITE_DELETE), aRec, pTab->nChange
-    );
+      case SQLITE_INTEGER: {
+        if( abPK[i] ){
+          i64 iVal = sessionGetI64(a);
+          rc = sqlite3_bind_int64(pSelect, i+1, iVal);
+        }
+        a += 8;
+        break;
+      }
 
-    /* Search for existing entry. If found, remove it from the hash table. 
-    ** Code below may link it back in.
-    */
-    for(pp=&pTab->apChange[iHash]; *pp; pp=&(*pp)->pNext){
-      int bPkOnly1 = 0;
-      int bPkOnly2 = 0;
-      if( pIter->bPatchset ){
-        bPkOnly1 = (*pp)->op==SQLITE_DELETE;
-        bPkOnly2 = op==SQLITE_DELETE;
+      case SQLITE_FLOAT: {
+        if( abPK[i] ){
+          double rVal;
+          i64 iVal = sessionGetI64(a);
+          memcpy(&rVal, &iVal, 8);
+          rc = sqlite3_bind_double(pSelect, i+1, rVal);
+        }
+        a += 8;
+        break;
       }
-      if( sessionChangeEqual(pTab, bPkOnly1, (*pp)->aRecord, bPkOnly2, aRec) ){
-        pExist = *pp;
-        *pp = (*pp)->pNext;
-        pTab->nEntry--;
+
+      case SQLITE_TEXT: {
+        int n;
+        a += sessionVarintGet(a, &n);
+        if( abPK[i] ){
+          rc = sqlite3_bind_text(pSelect, i+1, (char *)a, n, SQLITE_TRANSIENT);
+        }
+        a += n;
         break;
       }
-    }
 
-    rc = sessionChangeMerge(pTab, bRebase, 
-        pIter->bPatchset, pExist, op, bIndirect, aRec, nRec, &pChange
-    );
-    if( rc ) break;
-    if( pChange ){
-      pChange->pNext = pTab->apChange[iHash];
-      pTab->apChange[iHash] = pChange;
-      pTab->nEntry++;
+      default: {
+        int n;
+        assert( eType==SQLITE_BLOB );
+        a += sessionVarintGet(a, &n);
+        if( abPK[i] ){
+          rc = sqlite3_bind_blob(pSelect, i+1, a, n, SQLITE_TRANSIENT);
+        }
+        a += n;
+        break;
+      }
     }
   }
 
-  if( rc==SQLITE_OK ) rc = pIter->rc;
   return rc;
 }
 
 /*
-** Serialize a changeset (or patchset) based on all changesets (or patchsets)
-** added to the changegroup object passed as the first argument.
-**
-** If xOutput is not NULL, then the changeset/patchset is returned to the
-** user via one or more calls to xOutput, as with the other streaming
-** interfaces. 
-**
-** Or, if xOutput is NULL, then (*ppOut) is populated with a pointer to a
-** buffer containing the output changeset before this function returns. In
-** this case (*pnOut) is set to the size of the output buffer in bytes. It
-** is the responsibility of the caller to free the output buffer using
-** sqlite3_free() when it is no longer required.
+** This function is a no-op if *pRc is set to other than SQLITE_OK when it
+** is called. Otherwise, append a serialized table header (part of the binary 
+** changeset format) to buffer *pBuf. If an error occurs, set *pRc to an
+** SQLite error code before returning.
+*/
+static void sessionAppendTableHdr(
+  SessionBuffer *pBuf,            /* Append header to this buffer */
+  int bPatchset,                  /* Use the patchset format if true */
+  SessionTable *pTab,             /* Table object to append header for */
+  int *pRc                        /* IN/OUT: Error code */
+){
+  /* Write a table header */
+  sessionAppendByte(pBuf, (bPatchset ? 'P' : 'T'), pRc);
+  sessionAppendVarint(pBuf, pTab->nCol, pRc);
+  sessionAppendBlob(pBuf, pTab->abPK, pTab->nCol, pRc);
+  sessionAppendBlob(pBuf, (u8 *)pTab->zName, (int)strlen(pTab->zName)+1, pRc);
+}
+
+/*
+** Generate either a changeset (if argument bPatchset is zero) or a patchset
+** (if it is non-zero) based on the current contents of the session object
+** passed as the first argument.
 **
-** If successful, SQLITE_OK is returned. Or, if an error occurs, an SQLite
-** error code. If an error occurs and xOutput is NULL, (*ppOut) and (*pnOut)
-** are both set to 0 before returning.
+** If no error occurs, SQLITE_OK is returned and the new changeset/patchset
+** stored in output variables *pnChangeset and *ppChangeset. Or, if an error
+** occurs, an SQLite error code is returned and both output variables set 
+** to 0.
 */
-static int sessionChangegroupOutput(
-  sqlite3_changegroup *pGrp,
+static int sessionGenerateChangeset(
+  sqlite3_session *pSession,      /* Session object */
+  int bPatchset,                  /* True for patchset, false for changeset */
   int (*xOutput)(void *pOut, const void *pData, int nData),
-  void *pOut,
-  int *pnOut,
-  void **ppOut
+  void *pOut,                     /* First argument for xOutput */
+  int *pnChangeset,               /* OUT: Size of buffer at *ppChangeset */
+  void **ppChangeset              /* OUT: Buffer containing changeset */
 ){
-  int rc = SQLITE_OK;
-  SessionBuffer buf = {0, 0, 0};
-  SessionTable *pTab;
-  assert( xOutput==0 || (ppOut==0 && pnOut==0) );
+  sqlite3 *db = pSession->db;     /* Source database handle */
+  SessionTable *pTab;             /* Used to iterate through attached tables */
+  SessionBuffer buf = {0,0,0};    /* Buffer in which to accumlate changeset */
+  int rc;                         /* Return code */
 
-  /* Create the serialized output changeset based on the contents of the
-  ** hash tables attached to the SessionTable objects in list p->pList. 
-  */
-  for(pTab=pGrp->pList; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
-    int i;
-    if( pTab->nEntry==0 ) continue;
+  assert( xOutput==0 || (pnChangeset==0 && ppChangeset==0 ) );
 
-    sessionAppendTableHdr(&buf, pGrp->bPatch, pTab, &rc);
-    for(i=0; i<pTab->nChange; i++){
-      SessionChange *p;
-      for(p=pTab->apChange[i]; p; p=p->pNext){
-        sessionAppendByte(&buf, p->op, &rc);
-        sessionAppendByte(&buf, p->bIndirect, &rc);
-        sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc);
+  /* Zero the output variables in case an error occurs. If this session
+  ** object is already in the error state (sqlite3_session.rc != SQLITE_OK),
+  ** this call will be a no-op.  */
+  if( xOutput==0 ){
+    *pnChangeset = 0;
+    *ppChangeset = 0;
+  }
+
+  if( pSession->rc ) return pSession->rc;
+  rc = sqlite3_exec(pSession->db, "SAVEPOINT changeset", 0, 0, 0);
+  if( rc!=SQLITE_OK ) return rc;
+
+  sqlite3_mutex_enter(sqlite3_db_mutex(db));
+
+  for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
+    if( pTab->nEntry ){
+      const char *zName = pTab->zName;
+      int nCol;                   /* Number of columns in table */
+      u8 *abPK;                   /* Primary key array */
+      const char **azCol = 0;     /* Table columns */
+      int i;                      /* Used to iterate through hash buckets */
+      sqlite3_stmt *pSel = 0;     /* SELECT statement to query table pTab */
+      int nRewind = buf.nBuf;     /* Initial size of write buffer */
+      int nNoop;                  /* Size of buffer after writing tbl header */
+
+      /* Check the table schema is still Ok. */
+      rc = sessionTableInfo(db, pSession->zDb, zName, &nCol, 0, &azCol, &abPK);
+      if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){
+        rc = SQLITE_SCHEMA;
       }
-    }
 
-    if( rc==SQLITE_OK && xOutput && buf.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){
-      rc = xOutput(pOut, buf.aBuf, buf.nBuf);
-      buf.nBuf = 0;
+      /* Write a table header */
+      sessionAppendTableHdr(&buf, bPatchset, pTab, &rc);
+
+      /* Build and compile a statement to execute: */
+      if( rc==SQLITE_OK ){
+        rc = sessionSelectStmt(
+            db, pSession->zDb, zName, nCol, azCol, abPK, &pSel);
+      }
+
+      nNoop = buf.nBuf;
+      for(i=0; i<pTab->nChange && rc==SQLITE_OK; i++){
+        SessionChange *p;         /* Used to iterate through changes */
+
+        for(p=pTab->apChange[i]; rc==SQLITE_OK && p; p=p->pNext){
+          rc = sessionSelectBind(pSel, nCol, abPK, p);
+          if( rc!=SQLITE_OK ) continue;
+          if( sqlite3_step(pSel)==SQLITE_ROW ){
+            if( p->op==SQLITE_INSERT ){
+              int iCol;
+              sessionAppendByte(&buf, SQLITE_INSERT, &rc);
+              sessionAppendByte(&buf, p->bIndirect, &rc);
+              for(iCol=0; iCol<nCol; iCol++){
+                sessionAppendCol(&buf, pSel, iCol, &rc);
+              }
+            }else{
+              rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, abPK);
+            }
+          }else if( p->op!=SQLITE_INSERT ){
+            rc = sessionAppendDelete(&buf, bPatchset, p, nCol, abPK);
+          }
+          if( rc==SQLITE_OK ){
+            rc = sqlite3_reset(pSel);
+          }
+
+          /* If the buffer is now larger than SESSIONS_STRM_CHUNK_SIZE, pass
+          ** its contents to the xOutput() callback. */
+          if( xOutput 
+           && rc==SQLITE_OK 
+           && buf.nBuf>nNoop 
+           && buf.nBuf>SESSIONS_STRM_CHUNK_SIZE 
+          ){
+            rc = xOutput(pOut, (void*)buf.aBuf, buf.nBuf);
+            nNoop = -1;
+            buf.nBuf = 0;
+          }
+
+        }
+      }
+
+      sqlite3_finalize(pSel);
+      if( buf.nBuf==nNoop ){
+        buf.nBuf = nRewind;
+      }
+      sqlite3_free((char*)azCol);  /* cast works around VC++ bug */
     }
   }
 
   if( rc==SQLITE_OK ){
-    if( xOutput ){
-      if( buf.nBuf>0 ) rc = xOutput(pOut, buf.aBuf, buf.nBuf);
-    }else{
-      *ppOut = buf.aBuf;
-      *pnOut = buf.nBuf;
+    if( xOutput==0 ){
+      *pnChangeset = buf.nBuf;
+      *ppChangeset = buf.aBuf;
       buf.aBuf = 0;
+    }else if( buf.nBuf>0 ){
+      rc = xOutput(pOut, (void*)buf.aBuf, buf.nBuf);
     }
   }
-  sqlite3_free(buf.aBuf);
 
+  sqlite3_free(buf.aBuf);
+  sqlite3_exec(db, "RELEASE changeset", 0, 0, 0);
+  sqlite3_mutex_leave(sqlite3_db_mutex(db));
   return rc;
 }
 
 /*
-** Allocate a new, empty, sqlite3_changegroup.
+** Obtain a changeset object containing all changes recorded by the 
+** session object passed as the first argument.
+**
+** It is the responsibility of the caller to eventually free the buffer 
+** using sqlite3_free().
 */
-SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp){
-  int rc = SQLITE_OK;             /* Return code */
-  sqlite3_changegroup *p;         /* New object */
-  p = (sqlite3_changegroup*)sqlite3_malloc(sizeof(sqlite3_changegroup));
-  if( p==0 ){
-    rc = SQLITE_NOMEM;
-  }else{
-    memset(p, 0, sizeof(sqlite3_changegroup));
+SQLITE_API int sqlite3session_changeset(
+  sqlite3_session *pSession,      /* Session object */
+  int *pnChangeset,               /* OUT: Size of buffer at *ppChangeset */
+  void **ppChangeset              /* OUT: Buffer containing changeset */
+){
+  return sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset, ppChangeset);
+}
+
+/*
+** Streaming version of sqlite3session_changeset().
+*/
+SQLITE_API int sqlite3session_changeset_strm(
+  sqlite3_session *pSession,
+  int (*xOutput)(void *pOut, const void *pData, int nData),
+  void *pOut
+){
+  return sessionGenerateChangeset(pSession, 0, xOutput, pOut, 0, 0);
+}
+
+/*
+** Streaming version of sqlite3session_patchset().
+*/
+SQLITE_API int sqlite3session_patchset_strm(
+  sqlite3_session *pSession,
+  int (*xOutput)(void *pOut, const void *pData, int nData),
+  void *pOut
+){
+  return sessionGenerateChangeset(pSession, 1, xOutput, pOut, 0, 0);
+}
+
+/*
+** Obtain a patchset object containing all changes recorded by the 
+** session object passed as the first argument.
+**
+** It is the responsibility of the caller to eventually free the buffer 
+** using sqlite3_free().
+*/
+SQLITE_API int sqlite3session_patchset(
+  sqlite3_session *pSession,      /* Session object */
+  int *pnPatchset,                /* OUT: Size of buffer at *ppChangeset */
+  void **ppPatchset               /* OUT: Buffer containing changeset */
+){
+  return sessionGenerateChangeset(pSession, 1, 0, 0, pnPatchset, ppPatchset);
+}
+
+/*
+** Enable or disable the session object passed as the first argument.
+*/
+SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable){
+  int ret;
+  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
+  if( bEnable>=0 ){
+    pSession->bEnable = bEnable;
+  }
+  ret = pSession->bEnable;
+  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
+  return ret;
+}
+
+/*
+** Enable or disable the session object passed as the first argument.
+*/
+SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect){
+  int ret;
+  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
+  if( bIndirect>=0 ){
+    pSession->bIndirect = bIndirect;
+  }
+  ret = pSession->bIndirect;
+  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
+  return ret;
+}
+
+/*
+** Return true if there have been no changes to monitored tables recorded
+** by the session object passed as the only argument.
+*/
+SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession){
+  int ret = 0;
+  SessionTable *pTab;
+
+  sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
+  for(pTab=pSession->pTable; pTab && ret==0; pTab=pTab->pNext){
+    ret = (pTab->nEntry>0);
   }
-  *pp = p;
-  return rc;
+  sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
+
+  return (ret==0);
 }
 
 /*
-** Add the changeset currently stored in buffer pData, size nData bytes,
-** to changeset-group p.
+** Do the work for either sqlite3changeset_start() or start_strm().
 */
-SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup *pGrp, int nData, void *pData){
-  sqlite3_changeset_iter *pIter;  /* Iterator opened on pData/nData */
-  int rc;                         /* Return code */
+static int sessionChangesetStart(
+  sqlite3_changeset_iter **pp,    /* OUT: Changeset iterator handle */
+  int (*xInput)(void *pIn, void *pData, int *pnData),
+  void *pIn,
+  int nChangeset,                 /* Size of buffer pChangeset in bytes */
+  void *pChangeset                /* Pointer to buffer containing changeset */
+){
+  sqlite3_changeset_iter *pRet;   /* Iterator to return */
+  int nByte;                      /* Number of bytes to allocate for iterator */
 
-  rc = sqlite3changeset_start(&pIter, nData, pData);
-  if( rc==SQLITE_OK ){
-    rc = sessionChangesetToHash(pIter, pGrp, 0);
-  }
-  sqlite3changeset_finalize(pIter);
-  return rc;
+  assert( xInput==0 || (pChangeset==0 && nChangeset==0) );
+
+  /* Zero the output variable in case an error occurs. */
+  *pp = 0;
+
+  /* Allocate and initialize the iterator structure. */
+  nByte = sizeof(sqlite3_changeset_iter);
+  pRet = (sqlite3_changeset_iter *)sqlite3_malloc(nByte);
+  if( !pRet ) return SQLITE_NOMEM;
+  memset(pRet, 0, sizeof(sqlite3_changeset_iter));
+  pRet->in.aData = (u8 *)pChangeset;
+  pRet->in.nData = nChangeset;
+  pRet->in.xInput = xInput;
+  pRet->in.pIn = pIn;
+  pRet->in.bEof = (xInput ? 0 : 1);
+
+  /* Populate the output variable and return success. */
+  *pp = pRet;
+  return SQLITE_OK;
 }
 
 /*
-** Obtain a buffer containing a changeset representing the concatenation
-** of all changesets added to the group so far.
+** Create an iterator used to iterate through the contents of a changeset.
 */
-SQLITE_API int sqlite3changegroup_output(
-    sqlite3_changegroup *pGrp,
-    int *pnData,
-    void **ppData
+SQLITE_API int sqlite3changeset_start(
+  sqlite3_changeset_iter **pp,    /* OUT: Changeset iterator handle */
+  int nChangeset,                 /* Size of buffer pChangeset in bytes */
+  void *pChangeset                /* Pointer to buffer containing changeset */
 ){
-  return sessionChangegroupOutput(pGrp, 0, 0, pnData, ppData);
+  return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset);
 }
 
 /*
-** Streaming versions of changegroup_add().
+** Streaming version of sqlite3changeset_start().
 */
-SQLITE_API int sqlite3changegroup_add_strm(
-  sqlite3_changegroup *pGrp,
+SQLITE_API int sqlite3changeset_start_strm(
+  sqlite3_changeset_iter **pp,    /* OUT: Changeset iterator handle */
   int (*xInput)(void *pIn, void *pData, int *pnData),
   void *pIn
 ){
-  sqlite3_changeset_iter *pIter;  /* Iterator opened on pData/nData */
-  int rc;                         /* Return code */
-
-  rc = sqlite3changeset_start_strm(&pIter, xInput, pIn);
-  if( rc==SQLITE_OK ){
-    rc = sessionChangesetToHash(pIter, pGrp, 0);
-  }
-  sqlite3changeset_finalize(pIter);
-  return rc;
+  return sessionChangesetStart(pp, xInput, pIn, 0, 0);
 }
 
 /*
-** Streaming versions of changegroup_output().
+** If the SessionInput object passed as the only argument is a streaming
+** object and the buffer is full, discard some data to free up space.
 */
-SQLITE_API int sqlite3changegroup_output_strm(
-  sqlite3_changegroup *pGrp,
-  int (*xOutput)(void *pOut, const void *pData, int nData), 
-  void *pOut
-){
-  return sessionChangegroupOutput(pGrp, xOutput, pOut, 0, 0);
+static void sessionDiscardData(SessionInput *pIn){
+  if( pIn->xInput && pIn->iNext>=SESSIONS_STRM_CHUNK_SIZE ){
+    int nMove = pIn->buf.nBuf - pIn->iNext;
+    assert( nMove>=0 );
+    if( nMove>0 ){
+      memmove(pIn->buf.aBuf, &pIn->buf.aBuf[pIn->iNext], nMove);
+    }
+    pIn->buf.nBuf -= pIn->iNext;
+    pIn->iNext = 0;
+    pIn->nData = pIn->buf.nBuf;
+  }
 }
 
 /*
-** Delete a changegroup object.
+** Ensure that there are at least nByte bytes available in the buffer. Or,
+** if there are not nByte bytes remaining in the input, that all available
+** data is in the buffer.
+**
+** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise.
 */
-SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){
-  if( pGrp ){
-    sessionDeleteTable(pGrp->pList);
-    sqlite3_free(pGrp);
-  }
-}
+static int sessionInputBuffer(SessionInput *pIn, int nByte){
+  int rc = SQLITE_OK;
+  if( pIn->xInput ){
+    while( !pIn->bEof && (pIn->iNext+nByte)>=pIn->nData && rc==SQLITE_OK ){
+      int nNew = SESSIONS_STRM_CHUNK_SIZE;
 
-/* 
-** Combine two changesets together.
-*/
-SQLITE_API int sqlite3changeset_concat(
-  int nLeft,                      /* Number of bytes in lhs input */
-  void *pLeft,                    /* Lhs input changeset */
-  int nRight                      /* Number of bytes in rhs input */,
-  void *pRight,                   /* Rhs input changeset */
-  int *pnOut,                     /* OUT: Number of bytes in output changeset */
-  void **ppOut                    /* OUT: changeset (left <concat> right) */
-){
-  sqlite3_changegroup *pGrp;
-  int rc;
+      if( pIn->bNoDiscard==0 ) sessionDiscardData(pIn);
+      if( SQLITE_OK==sessionBufferGrow(&pIn->buf, nNew, &rc) ){
+        rc = pIn->xInput(pIn->pIn, &pIn->buf.aBuf[pIn->buf.nBuf], &nNew);
+        if( nNew==0 ){
+          pIn->bEof = 1;
+        }else{
+          pIn->buf.nBuf += nNew;
+        }
+      }
 
-  rc = sqlite3changegroup_new(&pGrp);
-  if( rc==SQLITE_OK ){
-    rc = sqlite3changegroup_add(pGrp, nLeft, pLeft);
-  }
-  if( rc==SQLITE_OK ){
-    rc = sqlite3changegroup_add(pGrp, nRight, pRight);
-  }
-  if( rc==SQLITE_OK ){
-    rc = sqlite3changegroup_output(pGrp, pnOut, ppOut);
+      pIn->aData = pIn->buf.aBuf;
+      pIn->nData = pIn->buf.nBuf;
+    }
   }
-  sqlite3changegroup_delete(pGrp);
-
   return rc;
 }
 
 /*
-** Streaming version of sqlite3changeset_concat().
+** When this function is called, *ppRec points to the start of a record
+** that contains nCol values. This function advances the pointer *ppRec
+** until it points to the byte immediately following that record.
 */
-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
+static void sessionSkipRecord(
+  u8 **ppRec,                     /* IN/OUT: Record pointer */
+  int nCol                        /* Number of values in record */
 ){
-  sqlite3_changegroup *pGrp;
-  int rc;
-
-  rc = sqlite3changegroup_new(&pGrp);
-  if( rc==SQLITE_OK ){
-    rc = sqlite3changegroup_add_strm(pGrp, xInputA, pInA);
-  }
-  if( rc==SQLITE_OK ){
-    rc = sqlite3changegroup_add_strm(pGrp, xInputB, pInB);
-  }
-  if( rc==SQLITE_OK ){
-    rc = sqlite3changegroup_output_strm(pGrp, xOutput, pOut);
+  u8 *aRec = *ppRec;
+  int i;
+  for(i=0; i<nCol; i++){
+    int eType = *aRec++;
+    if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
+      int nByte;
+      aRec += sessionVarintGet((u8*)aRec, &nByte);
+      aRec += nByte;
+    }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+      aRec += 8;
+    }
   }
-  sqlite3changegroup_delete(pGrp);
 
-  return rc;
+  *ppRec = aRec;
 }
 
 /*
-** Changeset rebaser handle.
-*/
-struct sqlite3_rebaser {
-  sqlite3_changegroup grp;        /* Hash table */
-};
-
-/*
-** Buffers a1 and a2 must both contain a sessions module record nCol
-** fields in size. This function appends an nCol sessions module 
-** record to buffer pBuf that is a copy of a1, except that for
-** each field that is undefined in a1[], swap in the field from a2[].
+** This function sets the value of the sqlite3_value object passed as the
+** first argument to a copy of the string or blob held in the aData[] 
+** buffer. SQLITE_OK is returned if successful, or SQLITE_NOMEM if an OOM
+** error occurs.
 */
-static void sessionAppendRecordMerge(
-  SessionBuffer *pBuf,            /* Buffer to append to */
-  int nCol,                       /* Number of columns in each record */
-  u8 *a1, int n1,                 /* Record 1 */
-  u8 *a2, int n2,                 /* Record 2 */
-  int *pRc                        /* IN/OUT: error code */
+static int sessionValueSetStr(
+  sqlite3_value *pVal,            /* Set the value of this object */
+  u8 *aData,                      /* Buffer containing string or blob data */
+  int nData,                      /* Size of buffer aData[] in bytes */
+  u8 enc                          /* String encoding (0 for blobs) */
 ){
-  sessionBufferGrow(pBuf, n1+n2, pRc);
-  if( *pRc==SQLITE_OK ){
-    int i;
-    u8 *pOut = &pBuf->aBuf[pBuf->nBuf];
-    for(i=0; i<nCol; i++){
-      int nn1 = sessionSerialLen(a1);
-      int nn2 = sessionSerialLen(a2);
-      if( *a1==0 || *a1==0xFF ){
-        memcpy(pOut, a2, nn2);
-        pOut += nn2;
-      }else{
-        memcpy(pOut, a1, nn1);
-        pOut += nn1;
-      }
-      a1 += nn1;
-      a2 += nn2;
-    }
-
-    pBuf->nBuf = pOut-pBuf->aBuf;
-    assert( pBuf->nBuf<=pBuf->nAlloc );
-  }
+  /* In theory this code could just pass SQLITE_TRANSIENT as the final
+  ** argument to sqlite3ValueSetStr() and have the copy created 
+  ** automatically. But doing so makes it difficult to detect any OOM
+  ** error. Hence the code to create the copy externally. */
+  u8 *aCopy = sqlite3_malloc(nData+1);
+  if( aCopy==0 ) return SQLITE_NOMEM;
+  memcpy(aCopy, aData, nData);
+  sqlite3ValueSetStr(pVal, nData, (char*)aCopy, enc, sqlite3_free);
+  return SQLITE_OK;
 }
 
 /*
-** This function is called when rebasing a local UPDATE change against one 
-** or more remote UPDATE changes. The aRec/nRec buffer contains the current
-** old.* and new.* records for the change. The rebase buffer (a single
-** record) is in aChange/nChange. The rebased change is appended to buffer
-** pBuf.
+** Deserialize a single record from a buffer in memory. See "RECORD FORMAT"
+** for details.
 **
-** Rebasing the UPDATE involves: 
+** When this function is called, *paChange points to the start of the record
+** to deserialize. Assuming no error occurs, *paChange is set to point to
+** one byte after the end of the same record before this function returns.
+** If the argument abPK is NULL, then the record contains nCol values. Or,
+** if abPK is other than NULL, then the record contains only the PK fields
+** (in other words, it is a patchset DELETE record).
 **
-**   * Removing any changes to fields for which the corresponding field
-**     in the rebase buffer is set to "replaced" (type 0xFF). If this
-**     means the UPDATE change updates no fields, nothing is appended
-**     to the output buffer.
+** If successful, each element of the apOut[] array (allocated by the caller)
+** is set to point to an sqlite3_value object containing the value read
+** from the corresponding position in the record. If that value is not
+** included in the record (i.e. because the record is part of an UPDATE change
+** and the field was not modified), the corresponding element of apOut[] is
+** set to NULL.
 **
-**   * For each field modified by the local change for which the 
-**     corresponding field in the rebase buffer is not "undefined" (0x00)
-**     or "replaced" (0xFF), the old.* value is replaced by the value
-**     in the rebase buffer.
+** It is the responsibility of the caller to free all sqlite_value structures
+** using sqlite3_free().
+**
+** If an error occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.
+** The apOut[] array may have been partially populated in this case.
 */
-static void sessionAppendPartialUpdate(
-  SessionBuffer *pBuf,            /* Append record here */
-  sqlite3_changeset_iter *pIter,  /* Iterator pointed at local change */
-  u8 *aRec, int nRec,             /* Local change */
-  u8 *aChange, int nChange,       /* Record to rebase against */
-  int *pRc                        /* IN/OUT: Return Code */
+static int sessionReadRecord(
+  SessionInput *pIn,              /* Input data */
+  int nCol,                       /* Number of values in record */
+  u8 *abPK,                       /* Array of primary key flags, or NULL */
+  sqlite3_value **apOut           /* Write values to this array */
 ){
-  sessionBufferGrow(pBuf, 2+nRec+nChange, pRc);
-  if( *pRc==SQLITE_OK ){
-    int bData = 0;
-    u8 *pOut = &pBuf->aBuf[pBuf->nBuf];
-    int i;
-    u8 *a1 = aRec;
-    u8 *a2 = aChange;
+  int i;                          /* Used to iterate through columns */
+  int rc = SQLITE_OK;
 
-    *pOut++ = SQLITE_UPDATE;
-    *pOut++ = pIter->bIndirect;
-    for(i=0; i<pIter->nCol; i++){
-      int n1 = sessionSerialLen(a1);
-      int n2 = sessionSerialLen(a2);
-      if( pIter->abPK[i] || a2[0]==0 ){
-        if( !pIter->abPK[i] ) bData = 1;
-        memcpy(pOut, a1, n1);
-        pOut += n1;
-      }else if( a2[0]!=0xFF ){
-        bData = 1;
-        memcpy(pOut, a2, n2);
-        pOut += n2;
+  for(i=0; i<nCol && rc==SQLITE_OK; i++){
+    int eType = 0;                /* Type of value (SQLITE_NULL, TEXT etc.) */
+    if( abPK && abPK[i]==0 ) continue;
+    rc = sessionInputBuffer(pIn, 9);
+    if( rc==SQLITE_OK ){
+      if( pIn->iNext>=pIn->nData ){
+        rc = SQLITE_CORRUPT_BKPT;
       }else{
-        *pOut++ = '\0';
+        eType = pIn->aData[pIn->iNext++];
+        assert( apOut[i]==0 );
+        if( eType ){
+          apOut[i] = sqlite3ValueNew(0);
+          if( !apOut[i] ) rc = SQLITE_NOMEM;
+        }
       }
-      a1 += n1;
-      a2 += n2;
     }
-    if( bData ){
-      a2 = aChange;
-      for(i=0; i<pIter->nCol; i++){
-        int n1 = sessionSerialLen(a1);
-        int n2 = sessionSerialLen(a2);
-        if( pIter->abPK[i] || a2[0]!=0xFF ){
-          memcpy(pOut, a1, n1);
-          pOut += n1;
+
+    if( rc==SQLITE_OK ){
+      u8 *aVal = &pIn->aData[pIn->iNext];
+      if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
+        int nByte;
+        pIn->iNext += sessionVarintGet(aVal, &nByte);
+        rc = sessionInputBuffer(pIn, nByte);
+        if( rc==SQLITE_OK ){
+          if( nByte<0 || nByte>pIn->nData-pIn->iNext ){
+            rc = SQLITE_CORRUPT_BKPT;
+          }else{
+            u8 enc = (eType==SQLITE_TEXT ? SQLITE_UTF8 : 0);
+            rc = sessionValueSetStr(apOut[i],&pIn->aData[pIn->iNext],nByte,enc);
+            pIn->iNext += nByte;
+          }
+        }
+      }
+      if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+        sqlite3_int64 v = sessionGetI64(aVal);
+        if( eType==SQLITE_INTEGER ){
+          sqlite3VdbeMemSetInt64(apOut[i], v);
         }else{
-          *pOut++ = '\0';
+          double d;
+          memcpy(&d, &v, 8);
+          sqlite3VdbeMemSetDouble(apOut[i], d);
         }
-        a1 += n1;
-        a2 += n2;
+        pIn->iNext += 8;
       }
-      pBuf->nBuf = (pOut - pBuf->aBuf);
     }
   }
+
+  return rc;
 }
 
 /*
-** pIter is configured to iterate through a changeset. This function rebases 
-** that changeset according to the current configuration of the rebaser 
-** object passed as the first argument. If no error occurs and argument xOutput
-** is not NULL, then the changeset is returned to the caller by invoking
-** xOutput zero or more times and SQLITE_OK returned. Or, if xOutput is NULL,
-** then (*ppOut) is set to point to a buffer containing the rebased changeset
-** before this function returns. In this case (*pnOut) is set to the size of
-** the buffer in bytes.  It is the responsibility of the caller to eventually
-** free the (*ppOut) buffer using sqlite3_free(). 
+** The input pointer currently points to the second byte of a table-header.
+** Specifically, to the following:
 **
-** If an error occurs, an SQLite error code is returned. If ppOut and
-** pnOut are not NULL, then the two output parameters are set to 0 before
-** returning.
+**   + number of columns in table (varint)
+**   + array of PK flags (1 byte per column),
+**   + table name (nul terminated).
+**
+** This function ensures that all of the above is present in the input 
+** buffer (i.e. that it can be accessed without any calls to xInput()).
+** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code.
+** The input pointer is not moved.
 */
-static int sessionRebase(
-  sqlite3_rebaser *p,             /* Rebaser hash table */
-  sqlite3_changeset_iter *pIter,  /* Input data */
-  int (*xOutput)(void *pOut, const void *pData, int nData),
-  void *pOut,                     /* Context for xOutput callback */
-  int *pnOut,                     /* OUT: Number of bytes in output changeset */
-  void **ppOut                    /* OUT: Inverse of pChangeset */
-){
+static int sessionChangesetBufferTblhdr(SessionInput *pIn, int *pnByte){
   int rc = SQLITE_OK;
-  u8 *aRec = 0;
-  int nRec = 0;
-  int bNew = 0;
-  SessionTable *pTab = 0;
-  SessionBuffer sOut = {0,0,0};
-
-  while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec, &bNew) ){
-    SessionChange *pChange = 0;
-    int bDone = 0;
-
-    if( bNew ){
-      const char *zTab = pIter->zTab;
-      for(pTab=p->grp.pList; pTab; pTab=pTab->pNext){
-        if( 0==sqlite3_stricmp(pTab->zName, zTab) ) break;
-      }
-      bNew = 0;
-
-      /* A patchset may not be rebased */
-      if( pIter->bPatchset ){
-        rc = SQLITE_ERROR;
-      }
-
-      /* Append a table header to the output for this new table */
-      sessionAppendByte(&sOut, pIter->bPatchset ? 'P' : 'T', &rc);
-      sessionAppendVarint(&sOut, pIter->nCol, &rc);
-      sessionAppendBlob(&sOut, pIter->abPK, pIter->nCol, &rc);
-      sessionAppendBlob(&sOut,(u8*)pIter->zTab,(int)strlen(pIter->zTab)+1,&rc);
-    }
-
-    if( pTab && rc==SQLITE_OK ){
-      int iHash = sessionChangeHash(pTab, 0, aRec, pTab->nChange);
-
-      for(pChange=pTab->apChange[iHash]; pChange; pChange=pChange->pNext){
-        if( sessionChangeEqual(pTab, 0, aRec, 0, pChange->aRecord) ){
-          break;
-        }
-      }
-    }
-
-    if( pChange ){
-      assert( pChange->op==SQLITE_DELETE || pChange->op==SQLITE_INSERT );
-      switch( pIter->op ){
-        case SQLITE_INSERT:
-          if( pChange->op==SQLITE_INSERT ){
-            bDone = 1;
-            if( pChange->bIndirect==0 ){
-              sessionAppendByte(&sOut, SQLITE_UPDATE, &rc);
-              sessionAppendByte(&sOut, pIter->bIndirect, &rc);
-              sessionAppendBlob(&sOut, pChange->aRecord, pChange->nRecord, &rc);
-              sessionAppendBlob(&sOut, aRec, nRec, &rc);
-            }
-          }
-          break;
-
-        case SQLITE_UPDATE:
-          bDone = 1;
-          if( pChange->op==SQLITE_DELETE ){
-            if( pChange->bIndirect==0 ){
-              u8 *pCsr = aRec;
-              sessionSkipRecord(&pCsr, pIter->nCol);
-              sessionAppendByte(&sOut, SQLITE_INSERT, &rc);
-              sessionAppendByte(&sOut, pIter->bIndirect, &rc);
-              sessionAppendRecordMerge(&sOut, pIter->nCol,
-                  pCsr, nRec-(pCsr-aRec), 
-                  pChange->aRecord, pChange->nRecord, &rc
-              );
-            }
-          }else{
-            sessionAppendPartialUpdate(&sOut, pIter,
-                aRec, nRec, pChange->aRecord, pChange->nRecord, &rc
-            );
-          }
-          break;
-
-        default:
-          assert( pIter->op==SQLITE_DELETE );
-          bDone = 1;
-          if( pChange->op==SQLITE_INSERT ){
-            sessionAppendByte(&sOut, SQLITE_DELETE, &rc);
-            sessionAppendByte(&sOut, pIter->bIndirect, &rc);
-            sessionAppendRecordMerge(&sOut, pIter->nCol,
-                pChange->aRecord, pChange->nRecord, aRec, nRec, &rc
-            );
-          }
-          break;
-      }
-    }
-
-    if( bDone==0 ){
-      sessionAppendByte(&sOut, pIter->op, &rc);
-      sessionAppendByte(&sOut, pIter->bIndirect, &rc);
-      sessionAppendBlob(&sOut, aRec, nRec, &rc);
-    }
-    if( rc==SQLITE_OK && xOutput && sOut.nBuf>SESSIONS_STRM_CHUNK_SIZE ){
-      rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
-      sOut.nBuf = 0;
-    }
-    if( rc ) break;
-  }
-
-  if( rc!=SQLITE_OK ){
-    sqlite3_free(sOut.aBuf);
-    memset(&sOut, 0, sizeof(sOut));
-  }
+  int nCol = 0;
+  int nRead = 0;
 
+  rc = sessionInputBuffer(pIn, 9);
   if( rc==SQLITE_OK ){
-    if( xOutput ){
-      if( sOut.nBuf>0 ){
-        rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
-      }
+    nRead += sessionVarintGet(&pIn->aData[pIn->iNext + nRead], &nCol);
+    /* The hard upper limit for the number of columns in an SQLite
+    ** database table is, according to sqliteLimit.h, 32676. So 
+    ** consider any table-header that purports to have more than 65536 
+    ** columns to be corrupt. This is convenient because otherwise, 
+    ** if the (nCol>65536) condition below were omitted, a sufficiently 
+    ** large value for nCol may cause nRead to wrap around and become 
+    ** negative. Leading to a crash. */
+    if( nCol<0 || nCol>65536 ){
+      rc = SQLITE_CORRUPT_BKPT;
     }else{
-      *ppOut = (void*)sOut.aBuf;
-      *pnOut = sOut.nBuf;
-      sOut.aBuf = 0;
+      rc = sessionInputBuffer(pIn, nRead+nCol+100);
+      nRead += nCol;
     }
   }
-  sqlite3_free(sOut.aBuf);
-  return rc;
-}
-
-/* 
-** Create a new rebaser object.
-*/
-SQLITE_API int sqlite3rebaser_create(sqlite3_rebaser **ppNew){
-  int rc = SQLITE_OK;
-  sqlite3_rebaser *pNew;
 
-  pNew = sqlite3_malloc(sizeof(sqlite3_rebaser));
-  if( pNew==0 ){
-    rc = SQLITE_NOMEM;
-  }else{
-    memset(pNew, 0, sizeof(sqlite3_rebaser));
+  while( rc==SQLITE_OK ){
+    while( (pIn->iNext + nRead)<pIn->nData && pIn->aData[pIn->iNext + nRead] ){
+      nRead++;
+    }
+    if( (pIn->iNext + nRead)<pIn->nData ) break;
+    rc = sessionInputBuffer(pIn, nRead + 100);
   }
-  *ppNew = pNew;
+  *pnByte = nRead+1;
   return rc;
 }
 
-/* 
-** Call this one or more times to configure a rebaser.
+/*
+** The input pointer currently points to the first byte of the first field
+** of a record consisting of nCol columns. This function ensures the entire
+** record is buffered. It does not move the input pointer.
+**
+** If successful, SQLITE_OK is returned and *pnByte is set to the size of
+** the record in bytes. Otherwise, an SQLite error code is returned. The
+** final value of *pnByte is undefined in this case.
 */
-SQLITE_API int sqlite3rebaser_configure(
-  sqlite3_rebaser *p, 
-  int nRebase, const void *pRebase
+static int sessionChangesetBufferRecord(
+  SessionInput *pIn,              /* Input data */
+  int nCol,                       /* Number of columns in record */
+  int *pnByte                     /* OUT: Size of record in bytes */
 ){
-  sqlite3_changeset_iter *pIter = 0;   /* Iterator opened on pData/nData */
-  int rc;                              /* Return code */
-  rc = sqlite3changeset_start(&pIter, nRebase, (void*)pRebase);
-  if( rc==SQLITE_OK ){
-    rc = sessionChangesetToHash(pIter, &p->grp, 1);
+  int rc = SQLITE_OK;
+  int nByte = 0;
+  int i;
+  for(i=0; rc==SQLITE_OK && i<nCol; i++){
+    int eType;
+    rc = sessionInputBuffer(pIn, nByte + 10);
+    if( rc==SQLITE_OK ){
+      eType = pIn->aData[pIn->iNext + nByte++];
+      if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
+        int n;
+        nByte += sessionVarintGet(&pIn->aData[pIn->iNext+nByte], &n);
+        nByte += n;
+        rc = sessionInputBuffer(pIn, nByte);
+      }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+        nByte += 8;
+      }
+    }
   }
-  sqlite3changeset_finalize(pIter);
+  *pnByte = nByte;
   return rc;
 }
 
-/* 
-** Rebase a changeset according to current rebaser configuration 
+/*
+** The input pointer currently points to the second byte of a table-header.
+** Specifically, to the following:
+**
+**   + number of columns in table (varint)
+**   + array of PK flags (1 byte per column),
+**   + table name (nul terminated).
+**
+** This function decodes the table-header and populates the p->nCol, 
+** p->zTab and p->abPK[] variables accordingly. The p->apValue[] array is 
+** also allocated or resized according to the new value of p->nCol. The
+** input pointer is left pointing to the byte following the table header.
+**
+** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code
+** is returned and the final values of the various fields enumerated above
+** are undefined.
 */
-SQLITE_API int sqlite3rebaser_rebase(
-  sqlite3_rebaser *p,
-  int nIn, const void *pIn, 
-  int *pnOut, void **ppOut 
-){
-  sqlite3_changeset_iter *pIter = 0;   /* Iterator to skip through input */  
-  int rc = sqlite3changeset_start(&pIter, nIn, (void*)pIn);
+static int sessionChangesetReadTblhdr(sqlite3_changeset_iter *p){
+  int rc;
+  int nCopy;
+  assert( p->rc==SQLITE_OK );
 
+  rc = sessionChangesetBufferTblhdr(&p->in, &nCopy);
   if( rc==SQLITE_OK ){
-    rc = sessionRebase(p, pIter, 0, 0, pnOut, ppOut);
-    sqlite3changeset_finalize(pIter);
+    int nByte;
+    int nVarint;
+    nVarint = sessionVarintGet(&p->in.aData[p->in.iNext], &p->nCol);
+    if( p->nCol>0 ){
+      nCopy -= nVarint;
+      p->in.iNext += nVarint;
+      nByte = p->nCol * sizeof(sqlite3_value*) * 2 + nCopy;
+      p->tblhdr.nBuf = 0;
+      sessionBufferGrow(&p->tblhdr, nByte, &rc);
+    }else{
+      rc = SQLITE_CORRUPT_BKPT;
+    }
   }
 
-  return rc;
-}
-
-/* 
-** Rebase a changeset according to current rebaser configuration 
-*/
-SQLITE_API int sqlite3rebaser_rebase_strm(
-  sqlite3_rebaser *p,
-  int (*xInput)(void *pIn, void *pData, int *pnData),
-  void *pIn,
-  int (*xOutput)(void *pOut, const void *pData, int nData),
-  void *pOut
-){
-  sqlite3_changeset_iter *pIter = 0;   /* Iterator to skip through input */  
-  int rc = sqlite3changeset_start_strm(&pIter, xInput, pIn);
-
   if( rc==SQLITE_OK ){
-    rc = sessionRebase(p, pIter, xOutput, pOut, 0, 0);
-    sqlite3changeset_finalize(pIter);
+    int iPK = sizeof(sqlite3_value*)*p->nCol*2;
+    memset(p->tblhdr.aBuf, 0, iPK);
+    memcpy(&p->tblhdr.aBuf[iPK], &p->in.aData[p->in.iNext], nCopy);
+    p->in.iNext += nCopy;
   }
 
-  return rc;
-}
-
-/* 
-** Destroy a rebaser object 
-*/
-SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p){
-  if( p ){
-    sessionDeleteTable(p->grp.pList);
-    sqlite3_free(p);
-  }
+  p->apValue = (sqlite3_value**)p->tblhdr.aBuf;
+  p->abPK = (u8*)&p->apValue[p->nCol*2];
+  p->zTab = (char*)&p->abPK[p->nCol];
+  return (p->rc = rc);
 }
 
-#endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */
-
-/************** End of sqlite3session.c **************************************/
-/************** Begin file json1.c *******************************************/
 /*
-** 2015-08-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.
-**
-******************************************************************************
+** Advance the changeset iterator to the next change.
 **
-** This SQLite extension implements JSON functions.  The interface is
-** modeled after MySQL JSON functions:
+** If both paRec and pnRec are NULL, then this function works like the public
+** API sqlite3changeset_next(). If SQLITE_ROW is returned, then the
+** sqlite3changeset_new() and old() APIs may be used to query for values.
 **
-**     https://dev.mysql.com/doc/refman/5.7/en/json.html
+** Otherwise, if paRec and pnRec are not NULL, then a pointer to the change
+** record is written to *paRec before returning and the number of bytes in
+** the record to *pnRec.
 **
-** For the time being, all JSON is stored as pure text.  (We might add
-** a JSONB type in the future which stores a binary encoding of JSON in
-** a BLOB, but there is no support for JSONB in the current implementation.
-** This implementation parses JSON text at 250 MB/s, so it is hard to see
-** how JSONB might improve on that.)
-*/
-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1)
-#if !defined(SQLITEINT_H)
-/* #include "sqlite3ext.h" */
-#endif
-SQLITE_EXTENSION_INIT1
-/* #include <assert.h> */
-/* #include <string.h> */
-/* #include <stdlib.h> */
-/* #include <stdarg.h> */
-
-/* Mark a function parameter as unused, to suppress nuisance compiler
-** warnings. */
-#ifndef UNUSED_PARAM
-# define UNUSED_PARAM(X)  (void)(X)
-#endif
-
-#ifndef LARGEST_INT64
-# define LARGEST_INT64  (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
-# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
-#endif
-
-/*
-** Versions of isspace(), isalnum() and isdigit() to which it is safe
-** to pass signed char values.
-*/
-#ifdef sqlite3Isdigit
-   /* Use the SQLite core versions if this routine is part of the
-   ** SQLite amalgamation */
-#  define safe_isdigit(x)  sqlite3Isdigit(x)
-#  define safe_isalnum(x)  sqlite3Isalnum(x)
-#  define safe_isxdigit(x) sqlite3Isxdigit(x)
-#else
-   /* Use the standard library for separate compilation */
-#include <ctype.h>  /* amalgamator: keep */
-#  define safe_isdigit(x)  isdigit((unsigned char)(x))
-#  define safe_isalnum(x)  isalnum((unsigned char)(x))
-#  define safe_isxdigit(x) isxdigit((unsigned char)(x))
-#endif
-
-/*
-** Growing our own isspace() routine this way is twice as fast as
-** the library isspace() function, resulting in a 7% overall performance
-** increase for the parser.  (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
-*/
-static const char jsonIsSpace[] = {
-  0, 0, 0, 0, 0, 0, 0, 0,     0, 1, 1, 0, 0, 1, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
-  1, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
-};
-#define safe_isspace(x) (jsonIsSpace[(unsigned char)x])
-
-#ifndef SQLITE_AMALGAMATION
-  /* Unsigned integer types.  These are already defined in the sqliteInt.h,
-  ** but the definitions need to be repeated for separate compilation. */
-  typedef sqlite3_uint64 u64;
-  typedef unsigned int u32;
-  typedef unsigned short int u16;
-  typedef unsigned char u8;
-#endif
-
-/* Objects */
-typedef struct JsonString JsonString;
-typedef struct JsonNode JsonNode;
-typedef struct JsonParse JsonParse;
-
-/* An instance of this object represents a JSON string
-** under construction.  Really, this is a generic string accumulator
-** that can be and is used to create strings other than JSON.
-*/
-struct JsonString {
-  sqlite3_context *pCtx;   /* Function context - put error messages here */
-  char *zBuf;              /* Append JSON content here */
-  u64 nAlloc;              /* Bytes of storage available in zBuf[] */
-  u64 nUsed;               /* Bytes of zBuf[] currently used */
-  u8 bStatic;              /* True if zBuf is static space */
-  u8 bErr;                 /* True if an error has been encountered */
-  char zSpace[100];        /* Initial static space */
-};
-
-/* JSON type values
-*/
-#define JSON_NULL     0
-#define JSON_TRUE     1
-#define JSON_FALSE    2
-#define JSON_INT      3
-#define JSON_REAL     4
-#define JSON_STRING   5
-#define JSON_ARRAY    6
-#define JSON_OBJECT   7
-
-/* The "subtype" set for JSON values */
-#define JSON_SUBTYPE  74    /* Ascii for "J" */
-
-/*
-** Names of the various JSON types:
-*/
-static const char * const jsonType[] = {
-  "null", "true", "false", "integer", "real", "text", "array", "object"
-};
-
-/* Bit values for the JsonNode.jnFlag field
+** Either way, this function returns SQLITE_ROW if the iterator is 
+** successfully advanced to the next change in the changeset, an SQLite 
+** error code if an error occurs, or SQLITE_DONE if there are no further 
+** changes in the changeset.
 */
-#define JNODE_RAW     0x01         /* Content is raw, not JSON encoded */
-#define JNODE_ESCAPE  0x02         /* Content is text with \ escapes */
-#define JNODE_REMOVE  0x04         /* Do not output */
-#define JNODE_REPLACE 0x08         /* Replace with JsonNode.u.iReplace */
-#define JNODE_PATCH   0x10         /* Patch with JsonNode.u.pPatch */
-#define JNODE_APPEND  0x20         /* More ARRAY/OBJECT entries at u.iAppend */
-#define JNODE_LABEL   0x40         /* Is a label of an object */
+static int sessionChangesetNext(
+  sqlite3_changeset_iter *p,      /* Changeset iterator */
+  u8 **paRec,                     /* If non-NULL, store record pointer here */
+  int *pnRec,                     /* If non-NULL, store size of record here */
+  int *pbNew                      /* If non-NULL, true if new table */
+){
+  int i;
+  u8 op;
 
+  assert( (paRec==0 && pnRec==0) || (paRec && pnRec) );
 
-/* A single node of parsed JSON
-*/
-struct JsonNode {
-  u8 eType;              /* One of the JSON_ type values */
-  u8 jnFlags;            /* JNODE flags */
-  u32 n;                 /* Bytes of content, or number of sub-nodes */
-  union {
-    const char *zJContent; /* Content for INT, REAL, and STRING */
-    u32 iAppend;           /* More terms for ARRAY and OBJECT */
-    u32 iKey;              /* Key for ARRAY objects in json_tree() */
-    u32 iReplace;          /* Replacement content for JNODE_REPLACE */
-    JsonNode *pPatch;      /* Node chain of patch for JNODE_PATCH */
-  } u;
-};
+  /* If the iterator is in the error-state, return immediately. */
+  if( p->rc!=SQLITE_OK ) return p->rc;
 
-/* A completely parsed JSON string
-*/
-struct JsonParse {
-  u32 nNode;         /* Number of slots of aNode[] used */
-  u32 nAlloc;        /* Number of slots of aNode[] allocated */
-  JsonNode *aNode;   /* Array of nodes containing the parse */
-  const char *zJson; /* Original JSON string */
-  u32 *aUp;          /* Index of parent of each node */
-  u8 oom;            /* Set to true if out of memory */
-  u8 nErr;           /* Number of errors seen */
-  u16 iDepth;        /* Nesting depth */
-  int nJson;         /* Length of the zJson string in bytes */
-};
+  /* Free the current contents of p->apValue[], if any. */
+  if( p->apValue ){
+    for(i=0; i<p->nCol*2; i++){
+      sqlite3ValueFree(p->apValue[i]);
+    }
+    memset(p->apValue, 0, sizeof(sqlite3_value*)*p->nCol*2);
+  }
 
-/*
-** Maximum nesting depth of JSON for this implementation.
-**
-** This limit is needed to avoid a stack overflow in the recursive
-** descent parser.  A depth of 2000 is far deeper than any sane JSON
-** should go.
-*/
-#define JSON_MAX_DEPTH  2000
+  /* Make sure the buffer contains at least 10 bytes of input data, or all
+  ** remaining data if there are less than 10 bytes available. This is
+  ** sufficient either for the 'T' or 'P' byte and the varint that follows
+  ** it, or for the two single byte values otherwise. */
+  p->rc = sessionInputBuffer(&p->in, 2);
+  if( p->rc!=SQLITE_OK ) return p->rc;
 
-/**************************************************************************
-** Utility routines for dealing with JsonString objects
-**************************************************************************/
+  /* If the iterator is already at the end of the changeset, return DONE. */
+  if( p->in.iNext>=p->in.nData ){
+    return SQLITE_DONE;
+  }
 
-/* Set the JsonString object to an empty string
-*/
-static void jsonZero(JsonString *p){
-  p->zBuf = p->zSpace;
-  p->nAlloc = sizeof(p->zSpace);
-  p->nUsed = 0;
-  p->bStatic = 1;
-}
+  sessionDiscardData(&p->in);
+  p->in.iCurrent = p->in.iNext;
 
-/* Initialize the JsonString object
-*/
-static void jsonInit(JsonString *p, sqlite3_context *pCtx){
-  p->pCtx = pCtx;
-  p->bErr = 0;
-  jsonZero(p);
-}
+  op = p->in.aData[p->in.iNext++];
+  while( op=='T' || op=='P' ){
+    if( pbNew ) *pbNew = 1;
+    p->bPatchset = (op=='P');
+    if( sessionChangesetReadTblhdr(p) ) return p->rc;
+    if( (p->rc = sessionInputBuffer(&p->in, 2)) ) return p->rc;
+    p->in.iCurrent = p->in.iNext;
+    if( p->in.iNext>=p->in.nData ) return SQLITE_DONE;
+    op = p->in.aData[p->in.iNext++];
+  }
 
+  if( p->zTab==0 ){
+    /* The first record in the changeset is not a table header. Must be a
+    ** corrupt changeset. */
+    assert( p->in.iNext==1 );
+    return (p->rc = SQLITE_CORRUPT_BKPT);
+  }
 
-/* Free all allocated memory and reset the JsonString object back to its
-** initial state.
-*/
-static void jsonReset(JsonString *p){
-  if( !p->bStatic ) sqlite3_free(p->zBuf);
-  jsonZero(p);
-}
+  p->op = op;
+  p->bIndirect = p->in.aData[p->in.iNext++];
+  if( p->op!=SQLITE_UPDATE && p->op!=SQLITE_DELETE && p->op!=SQLITE_INSERT ){
+    return (p->rc = SQLITE_CORRUPT_BKPT);
+  }
 
+  if( paRec ){ 
+    int nVal;                     /* Number of values to buffer */
+    if( p->bPatchset==0 && op==SQLITE_UPDATE ){
+      nVal = p->nCol * 2;
+    }else if( p->bPatchset && op==SQLITE_DELETE ){
+      nVal = 0;
+      for(i=0; i<p->nCol; i++) if( p->abPK[i] ) nVal++;
+    }else{
+      nVal = p->nCol;
+    }
+    p->rc = sessionChangesetBufferRecord(&p->in, nVal, pnRec);
+    if( p->rc!=SQLITE_OK ) return p->rc;
+    *paRec = &p->in.aData[p->in.iNext];
+    p->in.iNext += *pnRec;
+  }else{
 
-/* Report an out-of-memory (OOM) condition 
-*/
-static void jsonOom(JsonString *p){
-  p->bErr = 1;
-  sqlite3_result_error_nomem(p->pCtx);
-  jsonReset(p);
-}
+    /* If this is an UPDATE or DELETE, read the old.* record. */
+    if( p->op!=SQLITE_INSERT && (p->bPatchset==0 || p->op==SQLITE_DELETE) ){
+      u8 *abPK = p->bPatchset ? p->abPK : 0;
+      p->rc = sessionReadRecord(&p->in, p->nCol, abPK, p->apValue);
+      if( p->rc!=SQLITE_OK ) return p->rc;
+    }
 
-/* Enlarge pJson->zBuf so that it can hold at least N more bytes.
-** Return zero on success.  Return non-zero on an OOM error
-*/
-static int jsonGrow(JsonString *p, u32 N){
-  u64 nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10;
-  char *zNew;
-  if( p->bStatic ){
-    if( p->bErr ) return 1;
-    zNew = sqlite3_malloc64(nTotal);
-    if( zNew==0 ){
-      jsonOom(p);
-      return SQLITE_NOMEM;
+    /* If this is an INSERT or UPDATE, read the new.* record. */
+    if( p->op!=SQLITE_DELETE ){
+      p->rc = sessionReadRecord(&p->in, p->nCol, 0, &p->apValue[p->nCol]);
+      if( p->rc!=SQLITE_OK ) return p->rc;
     }
-    memcpy(zNew, p->zBuf, (size_t)p->nUsed);
-    p->zBuf = zNew;
-    p->bStatic = 0;
-  }else{
-    zNew = sqlite3_realloc64(p->zBuf, nTotal);
-    if( zNew==0 ){
-      jsonOom(p);
-      return SQLITE_NOMEM;
+
+    if( p->bPatchset && p->op==SQLITE_UPDATE ){
+      /* If this is an UPDATE that is part of a patchset, then all PK and
+      ** modified fields are present in the new.* record. The old.* record
+      ** is currently completely empty. This block shifts the PK fields from
+      ** new.* to old.*, to accommodate the code that reads these arrays.  */
+      for(i=0; i<p->nCol; i++){
+        assert( p->apValue[i]==0 );
+        if( p->abPK[i] ){
+          p->apValue[i] = p->apValue[i+p->nCol];
+          if( p->apValue[i]==0 ) return (p->rc = SQLITE_CORRUPT_BKPT);
+          p->apValue[i+p->nCol] = 0;
+        }
+      }
     }
-    p->zBuf = zNew;
   }
-  p->nAlloc = nTotal;
-  return SQLITE_OK;
-}
-
-/* Append N bytes from zIn onto the end of the JsonString string.
-*/
-static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
-  if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return;
-  memcpy(p->zBuf+p->nUsed, zIn, N);
-  p->nUsed += N;
-}
 
-/* Append formatted text (not to exceed N bytes) to the JsonString.
-*/
-static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
-  va_list ap;
-  if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return;
-  va_start(ap, zFormat);
-  sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap);
-  va_end(ap);
-  p->nUsed += (int)strlen(p->zBuf+p->nUsed);
+  return SQLITE_ROW;
 }
 
-/* Append a single character
+/*
+** Advance an iterator created by sqlite3changeset_start() to the next
+** change in the changeset. This function may return SQLITE_ROW, SQLITE_DONE
+** or SQLITE_CORRUPT.
+**
+** This function may not be called on iterators passed to a conflict handler
+** callback by changeset_apply().
 */
-static void jsonAppendChar(JsonString *p, char c){
-  if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return;
-  p->zBuf[p->nUsed++] = c;
+SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *p){
+  return sessionChangesetNext(p, 0, 0, 0);
 }
 
-/* Append a comma separator to the output buffer, if the previous
-** character is not '[' or '{'.
+/*
+** The following function extracts information on the current change
+** from a changeset iterator. It may only be called after changeset_next()
+** has returned SQLITE_ROW.
 */
-static void jsonAppendSeparator(JsonString *p){
-  char c;
-  if( p->nUsed==0 ) return;
-  c = p->zBuf[p->nUsed-1];
-  if( c!='[' && c!='{' ) jsonAppendChar(p, ',');
+SQLITE_API int sqlite3changeset_op(
+  sqlite3_changeset_iter *pIter,  /* Iterator handle */
+  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 if change is indirect */
+){
+  *pOp = pIter->op;
+  *pnCol = pIter->nCol;
+  *pzTab = pIter->zTab;
+  if( pbIndirect ) *pbIndirect = pIter->bIndirect;
+  return SQLITE_OK;
 }
 
-/* Append the N-byte string in zIn to the end of the JsonString string
-** under construction.  Enclose the string in "..." and escape
-** any double-quotes or backslash characters contained within the
-** string.
+/*
+** Return information regarding the PRIMARY KEY and number of columns in
+** the database table affected by the change that pIter currently points
+** to. This function may only be called after changeset_next() returns
+** SQLITE_ROW.
 */
-static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
-  u32 i;
-  if( (N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0 ) return;
-  p->zBuf[p->nUsed++] = '"';
-  for(i=0; i<N; i++){
-    unsigned char c = ((unsigned const char*)zIn)[i];
-    if( c=='"' || c=='\\' ){
-      json_simple_escape:
-      if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return;
-      p->zBuf[p->nUsed++] = '\\';
-    }else if( c<=0x1f ){
-      static const char aSpecial[] = {
-         0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0,
-         0, 0, 0, 0, 0, 0, 0, 0,   0,   0,   0, 0,   0,   0, 0, 0
-      };
-      assert( sizeof(aSpecial)==32 );
-      assert( aSpecial['\b']=='b' );
-      assert( aSpecial['\f']=='f' );
-      assert( aSpecial['\n']=='n' );
-      assert( aSpecial['\r']=='r' );
-      assert( aSpecial['\t']=='t' );
-      if( aSpecial[c] ){
-        c = aSpecial[c];
-        goto json_simple_escape;
-      }
-      if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return;
-      p->zBuf[p->nUsed++] = '\\';
-      p->zBuf[p->nUsed++] = 'u';
-      p->zBuf[p->nUsed++] = '0';
-      p->zBuf[p->nUsed++] = '0';
-      p->zBuf[p->nUsed++] = '0' + (c>>4);
-      c = "0123456789abcdef"[c&0xf];
-    }
-    p->zBuf[p->nUsed++] = c;
-  }
-  p->zBuf[p->nUsed++] = '"';
-  assert( p->nUsed<p->nAlloc );
+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 */
+){
+  *pabPK = pIter->abPK;
+  if( pnCol ) *pnCol = pIter->nCol;
+  return SQLITE_OK;
 }
 
 /*
-** Append a function parameter value to the JSON string under 
-** construction.
+** This function may only be called while the iterator is pointing to an
+** SQLITE_UPDATE or SQLITE_DELETE change (see sqlite3changeset_op()).
+** Otherwise, SQLITE_MISUSE is returned.
+**
+** It sets *ppValue to point to an sqlite3_value structure containing the
+** iVal'th value in the old.* record. Or, if that particular value is not
+** included in the record (because the change is an UPDATE and the field
+** was not modified and is not a PK column), set *ppValue to NULL.
+**
+** If value iVal is out-of-range, SQLITE_RANGE is returned and *ppValue is
+** not modified. Otherwise, SQLITE_OK.
 */
-static void jsonAppendValue(
-  JsonString *p,                 /* Append to this JSON string */
-  sqlite3_value *pValue          /* Value to append */
+SQLITE_API int sqlite3changeset_old(
+  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
+  int iVal,                       /* Index of old.* value to retrieve */
+  sqlite3_value **ppValue         /* OUT: Old value (or NULL pointer) */
 ){
-  switch( sqlite3_value_type(pValue) ){
-    case SQLITE_NULL: {
-      jsonAppendRaw(p, "null", 4);
-      break;
-    }
-    case SQLITE_INTEGER:
-    case SQLITE_FLOAT: {
-      const char *z = (const char*)sqlite3_value_text(pValue);
-      u32 n = (u32)sqlite3_value_bytes(pValue);
-      jsonAppendRaw(p, z, n);
-      break;
-    }
-    case SQLITE_TEXT: {
-      const char *z = (const char*)sqlite3_value_text(pValue);
-      u32 n = (u32)sqlite3_value_bytes(pValue);
-      if( sqlite3_value_subtype(pValue)==JSON_SUBTYPE ){
-        jsonAppendRaw(p, z, n);
-      }else{
-        jsonAppendString(p, z, n);
-      }
-      break;
-    }
-    default: {
-      if( p->bErr==0 ){
-        sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1);
-        p->bErr = 2;
-        jsonReset(p);
-      }
-      break;
-    }
+  if( pIter->op!=SQLITE_UPDATE && pIter->op!=SQLITE_DELETE ){
+    return SQLITE_MISUSE;
+  }
+  if( iVal<0 || iVal>=pIter->nCol ){
+    return SQLITE_RANGE;
   }
+  *ppValue = pIter->apValue[iVal];
+  return SQLITE_OK;
 }
 
-
-/* Make the JSON in p the result of the SQL function.
+/*
+** This function may only be called while the iterator is pointing to an
+** SQLITE_UPDATE or SQLITE_INSERT change (see sqlite3changeset_op()).
+** Otherwise, SQLITE_MISUSE is returned.
+**
+** It sets *ppValue to point to an sqlite3_value structure containing the
+** iVal'th value in the new.* record. Or, if that particular value is not
+** included in the record (because the change is an UPDATE and the field
+** was not modified), set *ppValue to NULL.
+**
+** If value iVal is out-of-range, SQLITE_RANGE is returned and *ppValue is
+** not modified. Otherwise, SQLITE_OK.
 */
-static void jsonResult(JsonString *p){
-  if( p->bErr==0 ){
-    sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, 
-                          p->bStatic ? SQLITE_TRANSIENT : sqlite3_free,
-                          SQLITE_UTF8);
-    jsonZero(p);
+SQLITE_API int sqlite3changeset_new(
+  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
+  int iVal,                       /* Index of new.* value to retrieve */
+  sqlite3_value **ppValue         /* OUT: New value (or NULL pointer) */
+){
+  if( pIter->op!=SQLITE_UPDATE && pIter->op!=SQLITE_INSERT ){
+    return SQLITE_MISUSE;
   }
-  assert( p->bStatic );
+  if( iVal<0 || iVal>=pIter->nCol ){
+    return SQLITE_RANGE;
+  }
+  *ppValue = pIter->apValue[pIter->nCol+iVal];
+  return SQLITE_OK;
 }
 
-/**************************************************************************
-** Utility routines for dealing with JsonNode and JsonParse objects
-**************************************************************************/
+/*
+** The following two macros are used internally. They are similar to the
+** sqlite3changeset_new() and sqlite3changeset_old() functions, except that
+** they omit all error checking and return a pointer to the requested value.
+*/
+#define sessionChangesetNew(pIter, iVal) (pIter)->apValue[(pIter)->nCol+(iVal)]
+#define sessionChangesetOld(pIter, iVal) (pIter)->apValue[(iVal)]
 
 /*
-** Return the number of consecutive JsonNode slots need to represent
-** the parsed JSON at pNode.  The minimum answer is 1.  For ARRAY and
-** OBJECT types, the number might be larger.
+** This function may only be called with a changeset iterator that has been
+** passed to an SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT 
+** conflict-handler function. Otherwise, SQLITE_MISUSE is returned.
 **
-** Appended elements are not counted.  The value returned is the number
-** by which the JsonNode counter should increment in order to go to the
-** next peer value.
+** If successful, *ppValue is set to point to an sqlite3_value structure
+** containing the iVal'th value of the conflicting record.
+**
+** If value iVal is out-of-range or some other error occurs, an SQLite error
+** code is returned. Otherwise, SQLITE_OK.
 */
-static u32 jsonNodeSize(JsonNode *pNode){
-  return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1;
+SQLITE_API int sqlite3changeset_conflict(
+  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
+  int iVal,                       /* Index of conflict record value to fetch */
+  sqlite3_value **ppValue         /* OUT: Value from conflicting row */
+){
+  if( !pIter->pConflict ){
+    return SQLITE_MISUSE;
+  }
+  if( iVal<0 || iVal>=pIter->nCol ){
+    return SQLITE_RANGE;
+  }
+  *ppValue = sqlite3_column_value(pIter->pConflict, iVal);
+  return SQLITE_OK;
 }
 
 /*
-** Reclaim all memory allocated by a JsonParse object.  But do not
-** delete the JsonParse object itself.
+** 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.
 */
-static void jsonParseReset(JsonParse *pParse){
-  sqlite3_free(pParse->aNode);
-  pParse->aNode = 0;
-  pParse->nNode = 0;
-  pParse->nAlloc = 0;
-  sqlite3_free(pParse->aUp);
-  pParse->aUp = 0;
+SQLITE_API int sqlite3changeset_fk_conflicts(
+  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
+  int *pnOut                      /* OUT: Number of FK violations */
+){
+  if( pIter->pConflict || pIter->apValue ){
+    return SQLITE_MISUSE;
+  }
+  *pnOut = pIter->nCol;
+  return SQLITE_OK;
 }
 
+
 /*
-** Free a JsonParse object that was obtained from sqlite3_malloc().
+** Finalize an iterator allocated with sqlite3changeset_start().
+**
+** This function may not be called on iterators passed to a conflict handler
+** callback by changeset_apply().
 */
-static void jsonParseFree(JsonParse *pParse){
-  jsonParseReset(pParse);
-  sqlite3_free(pParse);
+SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *p){
+  int rc = SQLITE_OK;
+  if( p ){
+    int i;                        /* Used to iterate through p->apValue[] */
+    rc = p->rc;
+    if( p->apValue ){
+      for(i=0; i<p->nCol*2; i++) sqlite3ValueFree(p->apValue[i]);
+    }
+    sqlite3_free(p->tblhdr.aBuf);
+    sqlite3_free(p->in.buf.aBuf);
+    sqlite3_free(p);
+  }
+  return rc;
 }
 
-/*
-** Convert the JsonNode pNode into a pure JSON string and
-** append to pOut.  Subsubstructure is also included.  Return
-** the number of JsonNode objects that are encoded.
-*/
-static void jsonRenderNode(
-  JsonNode *pNode,               /* The node to render */
-  JsonString *pOut,              /* Write JSON here */
-  sqlite3_value **aReplace       /* Replacement values */
+static int sessionChangesetInvert(
+  SessionInput *pInput,           /* Input changeset */
+  int (*xOutput)(void *pOut, const void *pData, int nData),
+  void *pOut,
+  int *pnInverted,                /* OUT: Number of bytes in output changeset */
+  void **ppInverted               /* OUT: Inverse of pChangeset */
 ){
-  if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){
-    if( pNode->jnFlags & JNODE_REPLACE ){
-      jsonAppendValue(pOut, aReplace[pNode->u.iReplace]);
-      return;
-    }
-    pNode = pNode->u.pPatch;
+  int rc = SQLITE_OK;             /* Return value */
+  SessionBuffer sOut;             /* Output buffer */
+  int nCol = 0;                   /* Number of cols in current table */
+  u8 *abPK = 0;                   /* PK array for current table */
+  sqlite3_value **apVal = 0;      /* Space for values for UPDATE inversion */
+  SessionBuffer sPK = {0, 0, 0};  /* PK array for current table */
+
+  /* Initialize the output buffer */
+  memset(&sOut, 0, sizeof(SessionBuffer));
+
+  /* Zero the output variables in case an error occurs. */
+  if( ppInverted ){
+    *ppInverted = 0;
+    *pnInverted = 0;
   }
-  switch( pNode->eType ){
-    default: {
-      assert( pNode->eType==JSON_NULL );
-      jsonAppendRaw(pOut, "null", 4);
-      break;
-    }
-    case JSON_TRUE: {
-      jsonAppendRaw(pOut, "true", 4);
-      break;
-    }
-    case JSON_FALSE: {
-      jsonAppendRaw(pOut, "false", 5);
-      break;
-    }
-    case JSON_STRING: {
-      if( pNode->jnFlags & JNODE_RAW ){
-        jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
+
+  while( 1 ){
+    u8 eType;
+
+    /* Test for EOF. */
+    if( (rc = sessionInputBuffer(pInput, 2)) ) goto finished_invert;
+    if( pInput->iNext>=pInput->nData ) break;
+    eType = pInput->aData[pInput->iNext];
+
+    switch( eType ){
+      case 'T': {
+        /* A 'table' record consists of:
+        **
+        **   * A constant 'T' character,
+        **   * Number of columns in said table (a varint),
+        **   * An array of nCol bytes (sPK),
+        **   * A nul-terminated table name.
+        */
+        int nByte;
+        int nVar;
+        pInput->iNext++;
+        if( (rc = sessionChangesetBufferTblhdr(pInput, &nByte)) ){
+          goto finished_invert;
+        }
+        nVar = sessionVarintGet(&pInput->aData[pInput->iNext], &nCol);
+        sPK.nBuf = 0;
+        sessionAppendBlob(&sPK, &pInput->aData[pInput->iNext+nVar], nCol, &rc);
+        sessionAppendByte(&sOut, eType, &rc);
+        sessionAppendBlob(&sOut, &pInput->aData[pInput->iNext], nByte, &rc);
+        if( rc ) goto finished_invert;
+
+        pInput->iNext += nByte;
+        sqlite3_free(apVal);
+        apVal = 0;
+        abPK = sPK.aBuf;
         break;
       }
-      /* Fall through into the next case */
-    }
-    case JSON_REAL:
-    case JSON_INT: {
-      jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
-      break;
-    }
-    case JSON_ARRAY: {
-      u32 j = 1;
-      jsonAppendChar(pOut, '[');
-      for(;;){
-        while( j<=pNode->n ){
-          if( (pNode[j].jnFlags & JNODE_REMOVE)==0 ){
-            jsonAppendSeparator(pOut);
-            jsonRenderNode(&pNode[j], pOut, aReplace);
-          }
-          j += jsonNodeSize(&pNode[j]);
-        }
-        if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
-        pNode = &pNode[pNode->u.iAppend];
-        j = 1;
+
+      case SQLITE_INSERT:
+      case SQLITE_DELETE: {
+        int nByte;
+        int bIndirect = pInput->aData[pInput->iNext+1];
+        int eType2 = (eType==SQLITE_DELETE ? SQLITE_INSERT : SQLITE_DELETE);
+        pInput->iNext += 2;
+        assert( rc==SQLITE_OK );
+        rc = sessionChangesetBufferRecord(pInput, nCol, &nByte);
+        sessionAppendByte(&sOut, eType2, &rc);
+        sessionAppendByte(&sOut, bIndirect, &rc);
+        sessionAppendBlob(&sOut, &pInput->aData[pInput->iNext], nByte, &rc);
+        pInput->iNext += nByte;
+        if( rc ) goto finished_invert;
+        break;
       }
-      jsonAppendChar(pOut, ']');
-      break;
-    }
-    case JSON_OBJECT: {
-      u32 j = 1;
-      jsonAppendChar(pOut, '{');
-      for(;;){
-        while( j<=pNode->n ){
-          if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){
-            jsonAppendSeparator(pOut);
-            jsonRenderNode(&pNode[j], pOut, aReplace);
-            jsonAppendChar(pOut, ':');
-            jsonRenderNode(&pNode[j+1], pOut, aReplace);
+
+      case SQLITE_UPDATE: {
+        int iCol;
+
+        if( 0==apVal ){
+          apVal = (sqlite3_value **)sqlite3_malloc(sizeof(apVal[0])*nCol*2);
+          if( 0==apVal ){
+            rc = SQLITE_NOMEM;
+            goto finished_invert;
           }
-          j += 1 + jsonNodeSize(&pNode[j+1]);
+          memset(apVal, 0, sizeof(apVal[0])*nCol*2);
         }
-        if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
-        pNode = &pNode[pNode->u.iAppend];
-        j = 1;
-      }
-      jsonAppendChar(pOut, '}');
-      break;
-    }
-  }
-}
 
-/*
-** Return a JsonNode and all its descendents as a JSON string.
-*/
-static void jsonReturnJson(
-  JsonNode *pNode,            /* Node to return */
-  sqlite3_context *pCtx,      /* Return value for this function */
-  sqlite3_value **aReplace    /* Array of replacement values */
-){
-  JsonString s;
-  jsonInit(&s, pCtx);
-  jsonRenderNode(pNode, &s, aReplace);
-  jsonResult(&s);
-  sqlite3_result_subtype(pCtx, JSON_SUBTYPE);
-}
+        /* Write the header for the new UPDATE change. Same as the original. */
+        sessionAppendByte(&sOut, eType, &rc);
+        sessionAppendByte(&sOut, pInput->aData[pInput->iNext+1], &rc);
 
-/*
-** Make the JsonNode the return value of the function.
-*/
-static void jsonReturn(
-  JsonNode *pNode,            /* Node to return */
-  sqlite3_context *pCtx,      /* Return value for this function */
-  sqlite3_value **aReplace    /* Array of replacement values */
-){
-  switch( pNode->eType ){
-    default: {
-      assert( pNode->eType==JSON_NULL );
-      sqlite3_result_null(pCtx);
-      break;
-    }
-    case JSON_TRUE: {
-      sqlite3_result_int(pCtx, 1);
-      break;
-    }
-    case JSON_FALSE: {
-      sqlite3_result_int(pCtx, 0);
-      break;
-    }
-    case JSON_INT: {
-      sqlite3_int64 i = 0;
-      const char *z = pNode->u.zJContent;
-      if( z[0]=='-' ){ z++; }
-      while( z[0]>='0' && z[0]<='9' ){
-        unsigned v = *(z++) - '0';
-        if( i>=LARGEST_INT64/10 ){
-          if( i>LARGEST_INT64/10 ) goto int_as_real;
-          if( z[0]>='0' && z[0]<='9' ) goto int_as_real;
-          if( v==9 ) goto int_as_real;
-          if( v==8 ){
-            if( pNode->u.zJContent[0]=='-' ){
-              sqlite3_result_int64(pCtx, SMALLEST_INT64);
-              goto int_done;
-            }else{
-              goto int_as_real;
-            }
-          }
+        /* Read the old.* and new.* records for the update change. */
+        pInput->iNext += 2;
+        rc = sessionReadRecord(pInput, nCol, 0, &apVal[0]);
+        if( rc==SQLITE_OK ){
+          rc = sessionReadRecord(pInput, nCol, 0, &apVal[nCol]);
         }
-        i = i*10 + v;
-      }
-      if( pNode->u.zJContent[0]=='-' ){ i = -i; }
-      sqlite3_result_int64(pCtx, i);
-      int_done:
-      break;
-      int_as_real: /* fall through to real */;
-    }
-    case JSON_REAL: {
-      double r;
-#ifdef SQLITE_AMALGAMATION
-      const char *z = pNode->u.zJContent;
-      sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
-#else
-      r = strtod(pNode->u.zJContent, 0);
-#endif
-      sqlite3_result_double(pCtx, r);
-      break;
-    }
-    case JSON_STRING: {
-#if 0 /* Never happens because JNODE_RAW is only set by json_set(),
-      ** json_insert() and json_replace() and those routines do not
-      ** call jsonReturn() */
-      if( pNode->jnFlags & JNODE_RAW ){
-        sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n,
-                            SQLITE_TRANSIENT);
-      }else 
-#endif
-      assert( (pNode->jnFlags & JNODE_RAW)==0 );
-      if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){
-        /* JSON formatted without any backslash-escapes */
-        sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2,
-                            SQLITE_TRANSIENT);
-      }else{
-        /* Translate JSON formatted string into raw text */
-        u32 i;
-        u32 n = pNode->n;
-        const char *z = pNode->u.zJContent;
-        char *zOut;
-        u32 j;
-        zOut = sqlite3_malloc( n+1 );
-        if( zOut==0 ){
-          sqlite3_result_error_nomem(pCtx);
-          break;
+
+        /* Write the new old.* record. Consists of the PK columns from the
+        ** original old.* record, and the other values from the original
+        ** new.* record. */
+        for(iCol=0; iCol<nCol; iCol++){
+          sqlite3_value *pVal = apVal[iCol + (abPK[iCol] ? 0 : nCol)];
+          sessionAppendValue(&sOut, pVal, &rc);
         }
-        for(i=1, j=0; i<n-1; i++){
-          char c = z[i];
-          if( c!='\\' ){
-            zOut[j++] = c;
-          }else{
-            c = z[++i];
-            if( c=='u' ){
-              u32 v = 0, k;
-              for(k=0; k<4; i++, k++){
-                assert( i<n-2 );
-                c = z[i+1];
-                assert( safe_isxdigit(c) );
-                if( c<='9' ) v = v*16 + c - '0';
-                else if( c<='F' ) v = v*16 + c - 'A' + 10;
-                else v = v*16 + c - 'a' + 10;
-              }
-              if( v==0 ) break;
-              if( v<=0x7f ){
-                zOut[j++] = (char)v;
-              }else if( v<=0x7ff ){
-                zOut[j++] = (char)(0xc0 | (v>>6));
-                zOut[j++] = 0x80 | (v&0x3f);
-              }else{
-                zOut[j++] = (char)(0xe0 | (v>>12));
-                zOut[j++] = 0x80 | ((v>>6)&0x3f);
-                zOut[j++] = 0x80 | (v&0x3f);
-              }
-            }else{
-              if( c=='b' ){
-                c = '\b';
-              }else if( c=='f' ){
-                c = '\f';
-              }else if( c=='n' ){
-                c = '\n';
-              }else if( c=='r' ){
-                c = '\r';
-              }else if( c=='t' ){
-                c = '\t';
-              }
-              zOut[j++] = c;
-            }
-          }
+
+        /* Write the new new.* record. Consists of a copy of all values
+        ** from the original old.* record, except for the PK columns, which
+        ** are set to "undefined". */
+        for(iCol=0; iCol<nCol; iCol++){
+          sqlite3_value *pVal = (abPK[iCol] ? 0 : apVal[iCol]);
+          sessionAppendValue(&sOut, pVal, &rc);
         }
-        zOut[j] = 0;
-        sqlite3_result_text(pCtx, zOut, j, sqlite3_free);
+
+        for(iCol=0; iCol<nCol*2; iCol++){
+          sqlite3ValueFree(apVal[iCol]);
+        }
+        memset(apVal, 0, sizeof(apVal[0])*nCol*2);
+        if( rc!=SQLITE_OK ){
+          goto finished_invert;
+        }
+
+        break;
       }
-      break;
+
+      default:
+        rc = SQLITE_CORRUPT_BKPT;
+        goto finished_invert;
     }
-    case JSON_ARRAY:
-    case JSON_OBJECT: {
-      jsonReturnJson(pNode, pCtx, aReplace);
-      break;
+
+    assert( rc==SQLITE_OK );
+    if( xOutput && sOut.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){
+      rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
+      sOut.nBuf = 0;
+      if( rc!=SQLITE_OK ) goto finished_invert;
     }
   }
+
+  assert( rc==SQLITE_OK );
+  if( pnInverted ){
+    *pnInverted = sOut.nBuf;
+    *ppInverted = sOut.aBuf;
+    sOut.aBuf = 0;
+  }else if( sOut.nBuf>0 ){
+    rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
+  }
+
+ finished_invert:
+  sqlite3_free(sOut.aBuf);
+  sqlite3_free(apVal);
+  sqlite3_free(sPK.aBuf);
+  return rc;
 }
 
-/* Forward reference */
-static int jsonParseAddNode(JsonParse*,u32,u32,const char*);
 
 /*
-** A macro to hint to the compiler that a function should not be
-** inlined.
+** Invert a changeset object.
 */
-#if defined(__GNUC__)
-#  define JSON_NOINLINE  __attribute__((noinline))
-#elif defined(_MSC_VER) && _MSC_VER>=1310
-#  define JSON_NOINLINE  __declspec(noinline)
-#else
-#  define JSON_NOINLINE
-#endif
+SQLITE_API int sqlite3changeset_invert(
+  int nChangeset,                 /* Number of bytes in input */
+  const void *pChangeset,         /* Input changeset */
+  int *pnInverted,                /* OUT: Number of bytes in output changeset */
+  void **ppInverted               /* OUT: Inverse of pChangeset */
+){
+  SessionInput sInput;
 
+  /* Set up the input stream */
+  memset(&sInput, 0, sizeof(SessionInput));
+  sInput.nData = nChangeset;
+  sInput.aData = (u8*)pChangeset;
 
-static JSON_NOINLINE int jsonParseAddNodeExpand(
-  JsonParse *pParse,        /* Append the node to this object */
-  u32 eType,                /* Node type */
-  u32 n,                    /* Content size or sub-node count */
-  const char *zContent      /* Content */
-){
-  u32 nNew;
-  JsonNode *pNew;
-  assert( pParse->nNode>=pParse->nAlloc );
-  if( pParse->oom ) return -1;
-  nNew = pParse->nAlloc*2 + 10;
-  pNew = sqlite3_realloc(pParse->aNode, sizeof(JsonNode)*nNew);
-  if( pNew==0 ){
-    pParse->oom = 1;
-    return -1;
-  }
-  pParse->nAlloc = nNew;
-  pParse->aNode = pNew;
-  assert( pParse->nNode<pParse->nAlloc );
-  return jsonParseAddNode(pParse, eType, n, zContent);
+  return sessionChangesetInvert(&sInput, 0, 0, pnInverted, ppInverted);
 }
 
 /*
-** Create a new JsonNode instance based on the arguments and append that
-** instance to the JsonParse.  Return the index in pParse->aNode[] of the
-** new node, or -1 if a memory allocation fails.
+** Streaming version of sqlite3changeset_invert().
 */
-static int jsonParseAddNode(
-  JsonParse *pParse,        /* Append the node to this object */
-  u32 eType,                /* Node type */
-  u32 n,                    /* Content size or sub-node count */
-  const char *zContent      /* Content */
+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
 ){
-  JsonNode *p;
-  if( pParse->nNode>=pParse->nAlloc ){
-    return jsonParseAddNodeExpand(pParse, eType, n, zContent);
-  }
-  p = &pParse->aNode[pParse->nNode];
-  p->eType = (u8)eType;
-  p->jnFlags = 0;
-  p->n = n;
-  p->u.zJContent = zContent;
-  return pParse->nNode++;
+  SessionInput sInput;
+  int rc;
+
+  /* Set up the input stream */
+  memset(&sInput, 0, sizeof(SessionInput));
+  sInput.xInput = xInput;
+  sInput.pIn = pIn;
+
+  rc = sessionChangesetInvert(&sInput, xOutput, pOut, 0, 0);
+  sqlite3_free(sInput.buf.aBuf);
+  return rc;
 }
 
+typedef struct SessionApplyCtx SessionApplyCtx;
+struct SessionApplyCtx {
+  sqlite3 *db;
+  sqlite3_stmt *pDelete;          /* DELETE statement */
+  sqlite3_stmt *pUpdate;          /* UPDATE statement */
+  sqlite3_stmt *pInsert;          /* INSERT statement */
+  sqlite3_stmt *pSelect;          /* SELECT statement */
+  int nCol;                       /* Size of azCol[] and abPK[] arrays */
+  const char **azCol;             /* Array of column names */
+  u8 *abPK;                       /* Boolean array - true if column is in PK */
+  int bStat1;                     /* True if table is sqlite_stat1 */
+  int bDeferConstraints;          /* True to defer constraints */
+  SessionBuffer constraints;      /* Deferred constraints are stored here */
+  SessionBuffer rebase;           /* Rebase information (if any) here */
+  int bRebaseStarted;             /* If table header is already in rebase */
+};
+
 /*
-** Return true if z[] begins with 4 (or more) hexadecimal digits
+** Formulate a statement to DELETE a row from database db. Assuming a table
+** structure like this:
+**
+**     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
+**
+** The DELETE statement looks like this:
+**
+**     DELETE FROM x WHERE a = :1 AND c = :3 AND (:5 OR b IS :2 AND d IS :4)
+**
+** Variable :5 (nCol+1) is a boolean. It should be set to 0 if we require
+** matching b and d values, or 1 otherwise. The second case comes up if the
+** conflict handler is invoked with NOTFOUND and returns CHANGESET_REPLACE.
+**
+** If successful, SQLITE_OK is returned and SessionApplyCtx.pDelete is left
+** pointing to the prepared version of the SQL statement.
 */
-static int jsonIs4Hex(const char *z){
+static int sessionDeleteRow(
+  sqlite3 *db,                    /* Database handle */
+  const char *zTab,               /* Table name */
+  SessionApplyCtx *p              /* Session changeset-apply context */
+){
   int i;
-  for(i=0; i<4; i++) if( !safe_isxdigit(z[i]) ) return 0;
-  return 1;
+  const char *zSep = "";
+  int rc = SQLITE_OK;
+  SessionBuffer buf = {0, 0, 0};
+  int nPk = 0;
+
+  sessionAppendStr(&buf, "DELETE FROM ", &rc);
+  sessionAppendIdent(&buf, zTab, &rc);
+  sessionAppendStr(&buf, " WHERE ", &rc);
+
+  for(i=0; i<p->nCol; i++){
+    if( p->abPK[i] ){
+      nPk++;
+      sessionAppendStr(&buf, zSep, &rc);
+      sessionAppendIdent(&buf, p->azCol[i], &rc);
+      sessionAppendStr(&buf, " = ?", &rc);
+      sessionAppendInteger(&buf, i+1, &rc);
+      zSep = " AND ";
+    }
+  }
+
+  if( nPk<p->nCol ){
+    sessionAppendStr(&buf, " AND (?", &rc);
+    sessionAppendInteger(&buf, p->nCol+1, &rc);
+    sessionAppendStr(&buf, " OR ", &rc);
+
+    zSep = "";
+    for(i=0; i<p->nCol; i++){
+      if( !p->abPK[i] ){
+        sessionAppendStr(&buf, zSep, &rc);
+        sessionAppendIdent(&buf, p->azCol[i], &rc);
+        sessionAppendStr(&buf, " IS ?", &rc);
+        sessionAppendInteger(&buf, i+1, &rc);
+        zSep = "AND ";
+      }
+    }
+    sessionAppendStr(&buf, ")", &rc);
+  }
+
+  if( rc==SQLITE_OK ){
+    rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pDelete, 0);
+  }
+  sqlite3_free(buf.aBuf);
+
+  return rc;
 }
 
 /*
-** Parse a single JSON value which begins at pParse->zJson[i].  Return the
-** index of the first character past the end of the value parsed.
+** Formulate and prepare a statement to UPDATE a row from database db. 
+** Assuming a table structure like this:
 **
-** Return negative for a syntax error.  Special cases:  return -2 if the
-** first non-whitespace character is '}' and return -3 if the first
-** non-whitespace character is ']'.
+**     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
+**
+** The UPDATE statement looks like this:
+**
+**     UPDATE x SET
+**     a = CASE WHEN ?2  THEN ?3  ELSE a END,
+**     b = CASE WHEN ?5  THEN ?6  ELSE b END,
+**     c = CASE WHEN ?8  THEN ?9  ELSE c END,
+**     d = CASE WHEN ?11 THEN ?12 ELSE d END
+**     WHERE a = ?1 AND c = ?7 AND (?13 OR 
+**       (?5==0 OR b IS ?4) AND (?11==0 OR d IS ?10) AND
+**     )
+**
+** For each column in the table, there are three variables to bind:
+**
+**     ?(i*3+1)    The old.* value of the column, if any.
+**     ?(i*3+2)    A boolean flag indicating that the value is being modified.
+**     ?(i*3+3)    The new.* value of the column, if any.
+**
+** Also, a boolean flag that, if set to true, causes the statement to update
+** a row even if the non-PK values do not match. This is required if the
+** conflict-handler is invoked with CHANGESET_DATA and returns
+** CHANGESET_REPLACE. This is variable "?(nCol*3+1)".
+**
+** If successful, SQLITE_OK is returned and SessionApplyCtx.pUpdate is left
+** pointing to the prepared version of the SQL statement.
 */
-static int jsonParseValue(JsonParse *pParse, u32 i){
-  char c;
-  u32 j;
-  int iThis;
-  int x;
-  JsonNode *pNode;
-  const char *z = pParse->zJson;
-  while( safe_isspace(z[i]) ){ i++; }
-  if( (c = z[i])=='{' ){
-    /* Parse object */
-    iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
-    if( iThis<0 ) return -1;
-    for(j=i+1;;j++){
-      while( safe_isspace(z[j]) ){ j++; }
-      if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
-      x = jsonParseValue(pParse, j);
-      if( x<0 ){
-        pParse->iDepth--;
-        if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1;
-        return -1;
-      }
-      if( pParse->oom ) return -1;
-      pNode = &pParse->aNode[pParse->nNode-1];
-      if( pNode->eType!=JSON_STRING ) return -1;
-      pNode->jnFlags |= JNODE_LABEL;
-      j = x;
-      while( safe_isspace(z[j]) ){ j++; }
-      if( z[j]!=':' ) return -1;
-      j++;
-      x = jsonParseValue(pParse, j);
-      pParse->iDepth--;
-      if( x<0 ) return -1;
-      j = x;
-      while( safe_isspace(z[j]) ){ j++; }
-      c = z[j];
-      if( c==',' ) continue;
-      if( c!='}' ) return -1;
-      break;
-    }
-    pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
-    return j+1;
-  }else if( c=='[' ){
-    /* Parse array */
-    iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
-    if( iThis<0 ) return -1;
-    for(j=i+1;;j++){
-      while( safe_isspace(z[j]) ){ j++; }
-      if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
-      x = jsonParseValue(pParse, j);
-      pParse->iDepth--;
-      if( x<0 ){
-        if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1;
-        return -1;
-      }
-      j = x;
-      while( safe_isspace(z[j]) ){ j++; }
-      c = z[j];
-      if( c==',' ) continue;
-      if( c!=']' ) return -1;
-      break;
-    }
-    pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
-    return j+1;
-  }else if( c=='"' ){
-    /* Parse string */
-    u8 jnFlags = 0;
-    j = i+1;
-    for(;;){
-      c = z[j];
-      if( (c & ~0x1f)==0 ){
-        /* Control characters are not allowed in strings */
-        return -1;
-      }
-      if( c=='\\' ){
-        c = z[++j];
-        if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
-           || c=='n' || c=='r' || c=='t'
-           || (c=='u' && jsonIs4Hex(z+j+1)) ){
-          jnFlags = JNODE_ESCAPE;
-        }else{
-          return -1;
-        }
-      }else if( c=='"' ){
-        break;
-      }
-      j++;
-    }
-    jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]);
-    if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags;
-    return j+1;
-  }else if( c=='n'
-         && strncmp(z+i,"null",4)==0
-         && !safe_isalnum(z[i+4]) ){
-    jsonParseAddNode(pParse, JSON_NULL, 0, 0);
-    return i+4;
-  }else if( c=='t'
-         && strncmp(z+i,"true",4)==0
-         && !safe_isalnum(z[i+4]) ){
-    jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
-    return i+4;
-  }else if( c=='f'
-         && strncmp(z+i,"false",5)==0
-         && !safe_isalnum(z[i+5]) ){
-    jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
-    return i+5;
-  }else if( c=='-' || (c>='0' && c<='9') ){
-    /* Parse number */
-    u8 seenDP = 0;
-    u8 seenE = 0;
-    assert( '-' < '0' );
-    if( c<='0' ){
-      j = c=='-' ? i+1 : i;
-      if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1;
+static int sessionUpdateRow(
+  sqlite3 *db,                    /* Database handle */
+  const char *zTab,               /* Table name */
+  SessionApplyCtx *p              /* Session changeset-apply context */
+){
+  int rc = SQLITE_OK;
+  int i;
+  const char *zSep = "";
+  SessionBuffer buf = {0, 0, 0};
+
+  /* Append "UPDATE tbl SET " */
+  sessionAppendStr(&buf, "UPDATE ", &rc);
+  sessionAppendIdent(&buf, zTab, &rc);
+  sessionAppendStr(&buf, " SET ", &rc);
+
+  /* Append the assignments */
+  for(i=0; i<p->nCol; i++){
+    sessionAppendStr(&buf, zSep, &rc);
+    sessionAppendIdent(&buf, p->azCol[i], &rc);
+    sessionAppendStr(&buf, " = CASE WHEN ?", &rc);
+    sessionAppendInteger(&buf, i*3+2, &rc);
+    sessionAppendStr(&buf, " THEN ?", &rc);
+    sessionAppendInteger(&buf, i*3+3, &rc);
+    sessionAppendStr(&buf, " ELSE ", &rc);
+    sessionAppendIdent(&buf, p->azCol[i], &rc);
+    sessionAppendStr(&buf, " END", &rc);
+    zSep = ", ";
+  }
+
+  /* Append the PK part of the WHERE clause */
+  sessionAppendStr(&buf, " WHERE ", &rc);
+  for(i=0; i<p->nCol; i++){
+    if( p->abPK[i] ){
+      sessionAppendIdent(&buf, p->azCol[i], &rc);
+      sessionAppendStr(&buf, " = ?", &rc);
+      sessionAppendInteger(&buf, i*3+1, &rc);
+      sessionAppendStr(&buf, " AND ", &rc);
     }
-    j = i+1;
-    for(;; j++){
-      c = z[j];
-      if( c>='0' && c<='9' ) continue;
-      if( c=='.' ){
-        if( z[j-1]=='-' ) return -1;
-        if( seenDP ) return -1;
-        seenDP = 1;
-        continue;
-      }
-      if( c=='e' || c=='E' ){
-        if( z[j-1]<'0' ) return -1;
-        if( seenE ) return -1;
-        seenDP = seenE = 1;
-        c = z[j+1];
-        if( c=='+' || c=='-' ){
-          j++;
-          c = z[j+1];
-        }
-        if( c<'0' || c>'9' ) return -1;
-        continue;
-      }
-      break;
+  }
+
+  /* Append the non-PK part of the WHERE clause */
+  sessionAppendStr(&buf, " (?", &rc);
+  sessionAppendInteger(&buf, p->nCol*3+1, &rc);
+  sessionAppendStr(&buf, " OR 1", &rc);
+  for(i=0; i<p->nCol; i++){
+    if( !p->abPK[i] ){
+      sessionAppendStr(&buf, " AND (?", &rc);
+      sessionAppendInteger(&buf, i*3+2, &rc);
+      sessionAppendStr(&buf, "=0 OR ", &rc);
+      sessionAppendIdent(&buf, p->azCol[i], &rc);
+      sessionAppendStr(&buf, " IS ?", &rc);
+      sessionAppendInteger(&buf, i*3+1, &rc);
+      sessionAppendStr(&buf, ")", &rc);
     }
-    if( z[j-1]<'0' ) return -1;
-    jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT,
-                        j - i, &z[i]);
-    return j;
-  }else if( c=='}' ){
-    return -2;  /* End of {...} */
-  }else if( c==']' ){
-    return -3;  /* End of [...] */
-  }else if( c==0 ){
-    return 0;   /* End of file */
-  }else{
-    return -1;  /* Syntax error */
   }
+  sessionAppendStr(&buf, ")", &rc);
+
+  if( rc==SQLITE_OK ){
+    rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pUpdate, 0);
+  }
+  sqlite3_free(buf.aBuf);
+
+  return rc;
 }
 
+
 /*
-** Parse a complete JSON string.  Return 0 on success or non-zero if there
-** are any errors.  If an error occurs, free all memory associated with
-** pParse.
+** Formulate and prepare an SQL statement to query table zTab by primary
+** key. Assuming the following table structure:
 **
-** pParse is uninitialized when this routine is called.
+**     CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
+**
+** The SELECT statement looks like this:
+**
+**     SELECT * FROM x WHERE a = ?1 AND c = ?3
+**
+** If successful, SQLITE_OK is returned and SessionApplyCtx.pSelect is left
+** pointing to the prepared version of the SQL statement.
 */
-static int jsonParse(
-  JsonParse *pParse,           /* Initialize and fill this JsonParse object */
-  sqlite3_context *pCtx,       /* Report errors here */
-  const char *zJson            /* Input JSON text to be parsed */
+static int sessionSelectRow(
+  sqlite3 *db,                    /* Database handle */
+  const char *zTab,               /* Table name */
+  SessionApplyCtx *p              /* Session changeset-apply context */
+){
+  return sessionSelectStmt(
+      db, "main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect);
+}
+
+/*
+** Formulate and prepare an INSERT statement to add a record to table zTab.
+** For example:
+**
+**     INSERT INTO main."zTab" VALUES(?1, ?2, ?3 ...);
+**
+** If successful, SQLITE_OK is returned and SessionApplyCtx.pInsert is left
+** pointing to the prepared version of the SQL statement.
+*/
+static int sessionInsertRow(
+  sqlite3 *db,                    /* Database handle */
+  const char *zTab,               /* Table name */
+  SessionApplyCtx *p              /* Session changeset-apply context */
 ){
+  int rc = SQLITE_OK;
   int i;
-  memset(pParse, 0, sizeof(*pParse));
-  if( zJson==0 ) return 1;
-  pParse->zJson = zJson;
-  i = jsonParseValue(pParse, 0);
-  if( pParse->oom ) i = -1;
-  if( i>0 ){
-    assert( pParse->iDepth==0 );
-    while( safe_isspace(zJson[i]) ) i++;
-    if( zJson[i] ) i = -1;
+  SessionBuffer buf = {0, 0, 0};
+
+  sessionAppendStr(&buf, "INSERT INTO main.", &rc);
+  sessionAppendIdent(&buf, zTab, &rc);
+  sessionAppendStr(&buf, "(", &rc);
+  for(i=0; i<p->nCol; i++){
+    if( i!=0 ) sessionAppendStr(&buf, ", ", &rc);
+    sessionAppendIdent(&buf, p->azCol[i], &rc);
   }
-  if( i<=0 ){
-    if( pCtx!=0 ){
-      if( pParse->oom ){
-        sqlite3_result_error_nomem(pCtx);
-      }else{
-        sqlite3_result_error(pCtx, "malformed JSON", -1);
-      }
-    }
-    jsonParseReset(pParse);
-    return 1;
+
+  sessionAppendStr(&buf, ") VALUES(?", &rc);
+  for(i=1; i<p->nCol; i++){
+    sessionAppendStr(&buf, ", ?", &rc);
   }
-  return 0;
+  sessionAppendStr(&buf, ")", &rc);
+
+  if( rc==SQLITE_OK ){
+    rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pInsert, 0);
+  }
+  sqlite3_free(buf.aBuf);
+  return rc;
 }
 
-/* Mark node i of pParse as being a child of iParent.  Call recursively
-** to fill in all the descendants of node i.
+static int sessionPrepare(sqlite3 *db, sqlite3_stmt **pp, const char *zSql){
+  return sqlite3_prepare_v2(db, zSql, -1, pp, 0);
+}
+
+/*
+** Prepare statements for applying changes to the sqlite_stat1 table.
+** These are similar to those created by sessionSelectRow(),
+** sessionInsertRow(), sessionUpdateRow() and sessionDeleteRow() for 
+** other tables.
 */
-static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){
-  JsonNode *pNode = &pParse->aNode[i];
-  u32 j;
-  pParse->aUp[i] = iParent;
-  switch( pNode->eType ){
-    case JSON_ARRAY: {
-      for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){
-        jsonParseFillInParentage(pParse, i+j, i);
-      }
-      break;
-    }
-    case JSON_OBJECT: {
-      for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j+1)+1){
-        pParse->aUp[i+j] = i;
-        jsonParseFillInParentage(pParse, i+j+1, i);
-      }
-      break;
-    }
-    default: {
-      break;
-    }
+static int sessionStat1Sql(sqlite3 *db, SessionApplyCtx *p){
+  int rc = sessionSelectRow(db, "sqlite_stat1", p);
+  if( rc==SQLITE_OK ){
+    rc = sessionPrepare(db, &p->pInsert,
+        "INSERT INTO main.sqlite_stat1 VALUES(?1, "
+        "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END, "
+        "?3)"
+    );
   }
+  if( rc==SQLITE_OK ){
+    rc = sessionPrepare(db, &p->pUpdate,
+        "UPDATE main.sqlite_stat1 SET "
+        "tbl = CASE WHEN ?2 THEN ?3 ELSE tbl END, "
+        "idx = CASE WHEN ?5 THEN ?6 ELSE idx END, "
+        "stat = CASE WHEN ?8 THEN ?9 ELSE stat END  "
+        "WHERE tbl=?1 AND idx IS "
+        "CASE WHEN length(?4)=0 AND typeof(?4)='blob' THEN NULL ELSE ?4 END "
+        "AND (?10 OR ?8=0 OR stat IS ?7)"
+    );
+  }
+  if( rc==SQLITE_OK ){
+    rc = sessionPrepare(db, &p->pDelete,
+        "DELETE FROM main.sqlite_stat1 WHERE tbl=?1 AND idx IS "
+        "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END "
+        "AND (?4 OR stat IS ?3)"
+    );
+  }
+  return rc;
 }
 
 /*
-** Compute the parentage of all nodes in a completed parse.
+** A wrapper around sqlite3_bind_value() that detects an extra problem. 
+** See comments in the body of this function for details.
 */
-static int jsonParseFindParents(JsonParse *pParse){
-  u32 *aUp;
-  assert( pParse->aUp==0 );
-  aUp = pParse->aUp = sqlite3_malloc( sizeof(u32)*pParse->nNode );
-  if( aUp==0 ){
-    pParse->oom = 1;
+static int sessionBindValue(
+  sqlite3_stmt *pStmt,            /* Statement to bind value to */
+  int i,                          /* Parameter number to bind to */
+  sqlite3_value *pVal             /* Value to bind */
+){
+  int eType = sqlite3_value_type(pVal);
+  /* COVERAGE: The (pVal->z==0) branch is never true using current versions
+  ** of SQLite. If a malloc fails in an sqlite3_value_xxx() function, either
+  ** the (pVal->z) variable remains as it was or the type of the value is
+  ** set to SQLITE_NULL.  */
+  if( (eType==SQLITE_TEXT || eType==SQLITE_BLOB) && pVal->z==0 ){
+    /* This condition occurs when an earlier OOM in a call to
+    ** sqlite3_value_text() or sqlite3_value_blob() (perhaps from within
+    ** a conflict-handler) has zeroed the pVal->z pointer. Return NOMEM. */
     return SQLITE_NOMEM;
   }
-  jsonParseFillInParentage(pParse, 0, 0);
-  return SQLITE_OK;
+  return sqlite3_bind_value(pStmt, i, pVal);
 }
 
 /*
-** Magic number used for the JSON parse cache in sqlite3_get_auxdata()
+** Iterator pIter must point to an SQLITE_INSERT entry. This function 
+** transfers new.* values from the current iterator entry to statement
+** pStmt. The table being inserted into has nCol columns.
+**
+** New.* value $i from the iterator is bound to variable ($i+1) of 
+** statement pStmt. If parameter abPK is NULL, all values from 0 to (nCol-1)
+** are transfered to the statement. Otherwise, if abPK is not NULL, it points
+** to an array nCol elements in size. In this case only those values for 
+** which abPK[$i] is true are read from the iterator and bound to the 
+** statement.
+**
+** An SQLite error code is returned if an error occurs. Otherwise, SQLITE_OK.
 */
-#define JSON_CACHE_ID  (-429938)
+static int sessionBindRow(
+  sqlite3_changeset_iter *pIter,  /* Iterator to read values from */
+  int(*xValue)(sqlite3_changeset_iter *, int, sqlite3_value **),
+  int nCol,                       /* Number of columns */
+  u8 *abPK,                       /* If not NULL, bind only if true */
+  sqlite3_stmt *pStmt             /* Bind values to this statement */
+){
+  int i;
+  int rc = SQLITE_OK;
+
+  /* Neither sqlite3changeset_old or sqlite3changeset_new can fail if the
+  ** argument iterator points to a suitable entry. Make sure that xValue 
+  ** is one of these to guarantee that it is safe to ignore the return 
+  ** in the code below. */
+  assert( xValue==sqlite3changeset_old || xValue==sqlite3changeset_new );
+
+  for(i=0; rc==SQLITE_OK && i<nCol; i++){
+    if( !abPK || abPK[i] ){
+      sqlite3_value *pVal;
+      (void)xValue(pIter, i, &pVal);
+      if( pVal==0 ){
+        /* The value in the changeset was "undefined". This indicates a
+        ** corrupt changeset blob.  */
+        rc = SQLITE_CORRUPT_BKPT;
+      }else{
+        rc = sessionBindValue(pStmt, i+1, pVal);
+      }
+    }
+  }
+  return rc;
+}
 
 /*
-** Obtain a complete parse of the JSON found in the first argument
-** of the argv array.  Use the sqlite3_get_auxdata() cache for this
-** parse if it is available.  If the cache is not available or if it
-** is no longer valid, parse the JSON again and return the new parse,
-** and also register the new parse so that it will be available for
-** future sqlite3_get_auxdata() calls.
+** SQL statement pSelect is as generated by the sessionSelectRow() function.
+** This function binds the primary key values from the change that changeset
+** iterator pIter points to to the SELECT and attempts to seek to the table
+** entry. If a row is found, the SELECT statement left pointing at the row 
+** and SQLITE_ROW is returned. Otherwise, if no row is found and no error
+** has occured, the statement is reset and SQLITE_OK is returned. If an
+** error occurs, the statement is reset and an SQLite error code is returned.
+**
+** If this function returns SQLITE_ROW, the caller must eventually reset() 
+** statement pSelect. If any other value is returned, the statement does
+** not require a reset().
+**
+** If the iterator currently points to an INSERT record, bind values from the
+** new.* record to the SELECT statement. Or, if it points to a DELETE or
+** UPDATE, bind values from the old.* record. 
 */
-static JsonParse *jsonParseCached(
-  sqlite3_context *pCtx,
-  sqlite3_value **argv
+static int sessionSeekToRow(
+  sqlite3 *db,                    /* Database handle */
+  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
+  u8 *abPK,                       /* Primary key flags array */
+  sqlite3_stmt *pSelect           /* SELECT statement from sessionSelectRow() */
 ){
-  const char *zJson = (const char*)sqlite3_value_text(argv[0]);
-  int nJson = sqlite3_value_bytes(argv[0]);
-  JsonParse *p;
-  if( zJson==0 ) return 0;
-  p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID);
-  if( p && p->nJson==nJson && memcmp(p->zJson,zJson,nJson)==0 ){
-    p->nErr = 0;
-    return p; /* The cached entry matches, so return it */
+  int rc;                         /* Return code */
+  int nCol;                       /* Number of columns in table */
+  int op;                         /* Changset operation (SQLITE_UPDATE etc.) */
+  const char *zDummy;             /* Unused */
+
+  sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
+  rc = sessionBindRow(pIter, 
+      op==SQLITE_INSERT ? sqlite3changeset_new : sqlite3changeset_old,
+      nCol, abPK, pSelect
+  );
+
+  if( rc==SQLITE_OK ){
+    rc = sqlite3_step(pSelect);
+    if( rc!=SQLITE_ROW ) rc = sqlite3_reset(pSelect);
   }
-  p = sqlite3_malloc( sizeof(*p) + nJson + 1 );
-  if( p==0 ){
-    sqlite3_result_error_nomem(pCtx);
-    return 0;
+
+  return rc;
+}
+
+/*
+** This function is called from within sqlite3changset_apply_v2() when
+** a conflict is encountered and resolved using conflict resolution
+** mode eType (either SQLITE_CHANGESET_OMIT or SQLITE_CHANGESET_REPLACE)..
+** It adds a conflict resolution record to the buffer in 
+** SessionApplyCtx.rebase, which will eventually be returned to the caller
+** of apply_v2() as the "rebase" buffer.
+**
+** Return SQLITE_OK if successful, or an SQLite error code otherwise.
+*/
+static int sessionRebaseAdd(
+  SessionApplyCtx *p,             /* Apply context */
+  int eType,                      /* Conflict resolution (OMIT or REPLACE) */
+  sqlite3_changeset_iter *pIter   /* Iterator pointing at current change */
+){
+  int rc = SQLITE_OK;
+  int i;
+  int eOp = pIter->op;
+  if( p->bRebaseStarted==0 ){
+    /* Append a table-header to the rebase buffer */
+    const char *zTab = pIter->zTab;
+    sessionAppendByte(&p->rebase, 'T', &rc);
+    sessionAppendVarint(&p->rebase, p->nCol, &rc);
+    sessionAppendBlob(&p->rebase, p->abPK, p->nCol, &rc);
+    sessionAppendBlob(&p->rebase, (u8*)zTab, (int)strlen(zTab)+1, &rc);
+    p->bRebaseStarted = 1;
   }
-  memset(p, 0, sizeof(*p));
-  p->zJson = (char*)&p[1];
-  memcpy((char*)p->zJson, zJson, nJson+1);
-  if( jsonParse(p, pCtx, p->zJson) ){
-    sqlite3_free(p);
-    return 0;
+
+  assert( eType==SQLITE_CHANGESET_REPLACE||eType==SQLITE_CHANGESET_OMIT );
+  assert( eOp==SQLITE_DELETE || eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE );
+
+  sessionAppendByte(&p->rebase, 
+      (eOp==SQLITE_DELETE ? SQLITE_DELETE : SQLITE_INSERT), &rc
+  );
+  sessionAppendByte(&p->rebase, (eType==SQLITE_CHANGESET_REPLACE), &rc);
+  for(i=0; i<p->nCol; i++){
+    sqlite3_value *pVal = 0;
+    if( eOp==SQLITE_DELETE || (eOp==SQLITE_UPDATE && p->abPK[i]) ){
+      sqlite3changeset_old(pIter, i, &pVal);
+    }else{
+      sqlite3changeset_new(pIter, i, &pVal);
+    }
+    sessionAppendValue(&p->rebase, pVal, &rc);
   }
-  p->nJson = nJson;
-  sqlite3_set_auxdata(pCtx, JSON_CACHE_ID, p, (void(*)(void*))jsonParseFree);
-  return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID);
+
+  return rc;
 }
 
 /*
-** Compare the OBJECT label at pNode against zKey,nKey.  Return true on
-** a match.
+** Invoke the conflict handler for the change that the changeset iterator
+** currently points to.
+**
+** Argument eType must be either CHANGESET_DATA or CHANGESET_CONFLICT.
+** If argument pbReplace is NULL, then the type of conflict handler invoked
+** depends solely on eType, as follows:
+**
+**    eType value                 Value passed to xConflict
+**    -------------------------------------------------
+**    CHANGESET_DATA              CHANGESET_NOTFOUND
+**    CHANGESET_CONFLICT          CHANGESET_CONSTRAINT
+**
+** Or, if pbReplace is not NULL, then an attempt is made to find an existing
+** record with the same primary key as the record about to be deleted, updated
+** or inserted. If such a record can be found, it is available to the conflict
+** handler as the "conflicting" record. In this case the type of conflict
+** handler invoked is as follows:
+**
+**    eType value         PK Record found?   Value passed to xConflict
+**    ----------------------------------------------------------------
+**    CHANGESET_DATA      Yes                CHANGESET_DATA
+**    CHANGESET_DATA      No                 CHANGESET_NOTFOUND
+**    CHANGESET_CONFLICT  Yes                CHANGESET_CONFLICT
+**    CHANGESET_CONFLICT  No                 CHANGESET_CONSTRAINT
+**
+** If pbReplace is not NULL, and a record with a matching PK is found, and
+** the conflict handler function returns SQLITE_CHANGESET_REPLACE, *pbReplace
+** is set to non-zero before returning SQLITE_OK.
+**
+** If the conflict handler returns SQLITE_CHANGESET_ABORT, SQLITE_ABORT is
+** returned. Or, if the conflict handler returns an invalid value, 
+** SQLITE_MISUSE. If the conflict handler returns SQLITE_CHANGESET_OMIT,
+** this function returns SQLITE_OK.
 */
-static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){
-  if( pNode->jnFlags & JNODE_RAW ){
-    if( pNode->n!=nKey ) return 0;
-    return strncmp(pNode->u.zJContent, zKey, nKey)==0;
+static int sessionConflictHandler(
+  int eType,                      /* Either CHANGESET_DATA or CONFLICT */
+  SessionApplyCtx *p,             /* changeset_apply() context */
+  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
+  int(*xConflict)(void *, int, sqlite3_changeset_iter*),
+  void *pCtx,                     /* First argument for conflict handler */
+  int *pbReplace                  /* OUT: Set to true if PK row is found */
+){
+  int res = 0;                    /* Value returned by conflict handler */
+  int rc;
+  int nCol;
+  int op;
+  const char *zDummy;
+
+  sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
+
+  assert( eType==SQLITE_CHANGESET_CONFLICT || eType==SQLITE_CHANGESET_DATA );
+  assert( SQLITE_CHANGESET_CONFLICT+1==SQLITE_CHANGESET_CONSTRAINT );
+  assert( SQLITE_CHANGESET_DATA+1==SQLITE_CHANGESET_NOTFOUND );
+
+  /* Bind the new.* PRIMARY KEY values to the SELECT statement. */
+  if( pbReplace ){
+    rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect);
   }else{
-    if( pNode->n!=nKey+2 ) return 0;
-    return strncmp(pNode->u.zJContent+1, zKey, nKey)==0;
+    rc = SQLITE_OK;
   }
-}
 
-/* forward declaration */
-static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**);
+  if( rc==SQLITE_ROW ){
+    /* There exists another row with the new.* primary key. */
+    pIter->pConflict = p->pSelect;
+    res = xConflict(pCtx, eType, pIter);
+    pIter->pConflict = 0;
+    rc = sqlite3_reset(p->pSelect);
+  }else if( rc==SQLITE_OK ){
+    if( p->bDeferConstraints && eType==SQLITE_CHANGESET_CONFLICT ){
+      /* Instead of invoking the conflict handler, append the change blob
+      ** to the SessionApplyCtx.constraints buffer. */
+      u8 *aBlob = &pIter->in.aData[pIter->in.iCurrent];
+      int nBlob = pIter->in.iNext - pIter->in.iCurrent;
+      sessionAppendBlob(&p->constraints, aBlob, nBlob, &rc);
+      return SQLITE_OK;
+    }else{
+      /* No other row with the new.* primary key. */
+      res = xConflict(pCtx, eType+1, pIter);
+      if( res==SQLITE_CHANGESET_REPLACE ) rc = SQLITE_MISUSE;
+    }
+  }
+
+  if( rc==SQLITE_OK ){
+    switch( res ){
+      case SQLITE_CHANGESET_REPLACE:
+        assert( pbReplace );
+        *pbReplace = 1;
+        break;
+
+      case SQLITE_CHANGESET_OMIT:
+        break;
+
+      case SQLITE_CHANGESET_ABORT:
+        rc = SQLITE_ABORT;
+        break;
+
+      default:
+        rc = SQLITE_MISUSE;
+        break;
+    }
+    if( rc==SQLITE_OK ){
+      rc = sessionRebaseAdd(p, res, pIter);
+    }
+  }
+
+  return rc;
+}
 
 /*
-** Search along zPath to find the node specified.  Return a pointer
-** to that node, or NULL if zPath is malformed or if there is no such
-** node.
+** Attempt to apply the change that the iterator passed as the first argument
+** currently points to to the database. If a conflict is encountered, invoke
+** the conflict handler callback.
 **
-** If pApnd!=0, then try to append new nodes to complete zPath if it is
-** possible to do so and if no existing node corresponds to zPath.  If
-** new nodes are appended *pApnd is set to 1.
+** If argument pbRetry is NULL, then ignore any CHANGESET_DATA conflict. If
+** one is encountered, update or delete the row with the matching primary key
+** instead. Or, if pbRetry is not NULL and a CHANGESET_DATA conflict occurs,
+** invoke the conflict handler. If it returns CHANGESET_REPLACE, set *pbRetry
+** to true before returning. In this case the caller will invoke this function
+** again, this time with pbRetry set to NULL.
+**
+** If argument pbReplace is NULL and a CHANGESET_CONFLICT conflict is 
+** encountered invoke the conflict handler with CHANGESET_CONSTRAINT instead.
+** Or, if pbReplace is not NULL, invoke it with CHANGESET_CONFLICT. If such
+** an invocation returns SQLITE_CHANGESET_REPLACE, set *pbReplace to true
+** before retrying. In this case the caller attempts to remove the conflicting
+** row before invoking this function again, this time with pbReplace set 
+** to NULL.
+**
+** If any conflict handler returns SQLITE_CHANGESET_ABORT, this function
+** returns SQLITE_ABORT. Otherwise, if no error occurs, SQLITE_OK is 
+** returned.
 */
-static JsonNode *jsonLookupStep(
-  JsonParse *pParse,      /* The JSON to search */
-  u32 iRoot,              /* Begin the search at this node */
-  const char *zPath,      /* The path to search */
-  int *pApnd,             /* Append nodes to complete path if not NULL */
-  const char **pzErr      /* Make *pzErr point to any syntax error in zPath */
+static int sessionApplyOneOp(
+  sqlite3_changeset_iter *pIter,  /* Changeset iterator */
+  SessionApplyCtx *p,             /* changeset_apply() context */
+  int(*xConflict)(void *, int, sqlite3_changeset_iter *),
+  void *pCtx,                     /* First argument for the conflict handler */
+  int *pbReplace,                 /* OUT: True to remove PK row and retry */
+  int *pbRetry                    /* OUT: True to retry. */
 ){
-  u32 i, j, nKey;
-  const char *zKey;
-  JsonNode *pRoot = &pParse->aNode[iRoot];
-  if( zPath[0]==0 ) return pRoot;
-  if( zPath[0]=='.' ){
-    if( pRoot->eType!=JSON_OBJECT ) return 0;
-    zPath++;
-    if( zPath[0]=='"' ){
-      zKey = zPath + 1;
-      for(i=1; zPath[i] && zPath[i]!='"'; i++){}
-      nKey = i-1;
-      if( zPath[i] ){
-        i++;
-      }else{
-        *pzErr = zPath;
-        return 0;
-      }
-    }else{
-      zKey = zPath;
-      for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){}
-      nKey = i;
+  const char *zDummy;
+  int op;
+  int nCol;
+  int rc = SQLITE_OK;
+
+  assert( p->pDelete && p->pUpdate && p->pInsert && p->pSelect );
+  assert( p->azCol && p->abPK );
+  assert( !pbReplace || *pbReplace==0 );
+
+  sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
+
+  if( op==SQLITE_DELETE ){
+
+    /* Bind values to the DELETE statement. If conflict handling is required,
+    ** bind values for all columns and set bound variable (nCol+1) to true.
+    ** Or, if conflict handling is not required, bind just the PK column
+    ** values and, if it exists, set (nCol+1) to false. Conflict handling
+    ** is not required if:
+    **
+    **   * this is a patchset, or
+    **   * (pbRetry==0), or
+    **   * all columns of the table are PK columns (in this case there is
+    **     no (nCol+1) variable to bind to).
+    */
+    u8 *abPK = (pIter->bPatchset ? p->abPK : 0);
+    rc = sessionBindRow(pIter, sqlite3changeset_old, nCol, abPK, p->pDelete);
+    if( rc==SQLITE_OK && sqlite3_bind_parameter_count(p->pDelete)>nCol ){
+      rc = sqlite3_bind_int(p->pDelete, nCol+1, (pbRetry==0 || abPK));
     }
-    if( nKey==0 ){
-      *pzErr = zPath;
-      return 0;
+    if( rc!=SQLITE_OK ) return rc;
+
+    sqlite3_step(p->pDelete);
+    rc = sqlite3_reset(p->pDelete);
+    if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
+      rc = sessionConflictHandler(
+          SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
+      );
+    }else if( (rc&0xff)==SQLITE_CONSTRAINT ){
+      rc = sessionConflictHandler(
+          SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0
+      );
     }
-    j = 1;
-    for(;;){
-      while( j<=pRoot->n ){
-        if( jsonLabelCompare(pRoot+j, zKey, nKey) ){
-          return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr);
-        }
-        j++;
-        j += jsonNodeSize(&pRoot[j]);
+
+  }else if( op==SQLITE_UPDATE ){
+    int i;
+
+    /* Bind values to the UPDATE statement. */
+    for(i=0; rc==SQLITE_OK && i<nCol; i++){
+      sqlite3_value *pOld = sessionChangesetOld(pIter, i);
+      sqlite3_value *pNew = sessionChangesetNew(pIter, i);
+
+      sqlite3_bind_int(p->pUpdate, i*3+2, !!pNew);
+      if( pOld ){
+        rc = sessionBindValue(p->pUpdate, i*3+1, pOld);
       }
-      if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
-      iRoot += pRoot->u.iAppend;
-      pRoot = &pParse->aNode[iRoot];
-      j = 1;
-    }
-    if( pApnd ){
-      u32 iStart, iLabel;
-      JsonNode *pNode;
-      iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
-      iLabel = jsonParseAddNode(pParse, JSON_STRING, i, zPath);
-      zPath += i;
-      pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
-      if( pParse->oom ) return 0;
-      if( pNode ){
-        pRoot = &pParse->aNode[iRoot];
-        pRoot->u.iAppend = iStart - iRoot;
-        pRoot->jnFlags |= JNODE_APPEND;
-        pParse->aNode[iLabel].jnFlags |= JNODE_RAW;
+      if( rc==SQLITE_OK && pNew ){
+        rc = sessionBindValue(p->pUpdate, i*3+3, pNew);
       }
-      return pNode;
     }
-  }else if( zPath[0]=='[' && safe_isdigit(zPath[1]) ){
-    if( pRoot->eType!=JSON_ARRAY ) return 0;
-    i = 0;
-    j = 1;
-    while( safe_isdigit(zPath[j]) ){
-      i = i*10 + zPath[j] - '0';
-      j++;
+    if( rc==SQLITE_OK ){
+      sqlite3_bind_int(p->pUpdate, nCol*3+1, pbRetry==0 || pIter->bPatchset);
     }
-    if( zPath[j]!=']' ){
-      *pzErr = zPath;
-      return 0;
+    if( rc!=SQLITE_OK ) return rc;
+
+    /* Attempt the UPDATE. In the case of a NOTFOUND or DATA conflict,
+    ** the result will be SQLITE_OK with 0 rows modified. */
+    sqlite3_step(p->pUpdate);
+    rc = sqlite3_reset(p->pUpdate);
+
+    if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
+      /* A NOTFOUND or DATA error. Search the table to see if it contains
+      ** a row with a matching primary key. If so, this is a DATA conflict.
+      ** Otherwise, if there is no primary key match, it is a NOTFOUND. */
+
+      rc = sessionConflictHandler(
+          SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
+      );
+
+    }else if( (rc&0xff)==SQLITE_CONSTRAINT ){
+      /* This is always a CONSTRAINT conflict. */
+      rc = sessionConflictHandler(
+          SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0
+      );
     }
-    zPath += j + 1;
-    j = 1;
-    for(;;){
-      while( j<=pRoot->n && (i>0 || (pRoot[j].jnFlags & JNODE_REMOVE)!=0) ){
-        if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 ) i--;
-        j += jsonNodeSize(&pRoot[j]);
+
+  }else{
+    assert( op==SQLITE_INSERT );
+    if( p->bStat1 ){
+      /* Check if there is a conflicting row. For sqlite_stat1, this needs
+      ** to be done using a SELECT, as there is no PRIMARY KEY in the 
+      ** database schema to throw an exception if a duplicate is inserted.  */
+      rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect);
+      if( rc==SQLITE_ROW ){
+        rc = SQLITE_CONSTRAINT;
+        sqlite3_reset(p->pSelect);
       }
-      if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
-      iRoot += pRoot->u.iAppend;
-      pRoot = &pParse->aNode[iRoot];
-      j = 1;
     }
-    if( j<=pRoot->n ){
-      return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr);
+
+    if( rc==SQLITE_OK ){
+      rc = sessionBindRow(pIter, sqlite3changeset_new, nCol, 0, p->pInsert);
+      if( rc!=SQLITE_OK ) return rc;
+
+      sqlite3_step(p->pInsert);
+      rc = sqlite3_reset(p->pInsert);
     }
-    if( i==0 && pApnd ){
-      u32 iStart;
-      JsonNode *pNode;
-      iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0);
-      pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
-      if( pParse->oom ) return 0;
-      if( pNode ){
-        pRoot = &pParse->aNode[iRoot];
-        pRoot->u.iAppend = iStart - iRoot;
-        pRoot->jnFlags |= JNODE_APPEND;
-      }
-      return pNode;
+
+    if( (rc&0xff)==SQLITE_CONSTRAINT ){
+      rc = sessionConflictHandler(
+          SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, pbReplace
+      );
     }
-  }else{
-    *pzErr = zPath;
   }
-  return 0;
+
+  return rc;
 }
 
 /*
-** Append content to pParse that will complete zPath.  Return a pointer
-** to the inserted node, or return NULL if the append fails.
+** Attempt to apply the change that the iterator passed as the first argument
+** currently points to to the database. If a conflict is encountered, invoke
+** the conflict handler callback.
+**
+** The difference between this function and sessionApplyOne() is that this
+** function handles the case where the conflict-handler is invoked and 
+** returns SQLITE_CHANGESET_REPLACE - indicating that the change should be
+** retried in some manner.
 */
-static JsonNode *jsonLookupAppend(
-  JsonParse *pParse,     /* Append content to the JSON parse */
-  const char *zPath,     /* Description of content to append */
-  int *pApnd,            /* Set this flag to 1 */
-  const char **pzErr     /* Make this point to any syntax error */
+static int sessionApplyOneWithRetry(
+  sqlite3 *db,                    /* Apply change to "main" db of this handle */
+  sqlite3_changeset_iter *pIter,  /* Changeset iterator to read change from */
+  SessionApplyCtx *pApply,        /* Apply context */
+  int(*xConflict)(void*, int, sqlite3_changeset_iter*),
+  void *pCtx                      /* First argument passed to xConflict */
 ){
-  *pApnd = 1;
-  if( zPath[0]==0 ){
-    jsonParseAddNode(pParse, JSON_NULL, 0, 0);
-    return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1];
-  }
-  if( zPath[0]=='.' ){
-    jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
-  }else if( strncmp(zPath,"[0]",3)==0 ){
-    jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
-  }else{
-    return 0;
+  int bReplace = 0;
+  int bRetry = 0;
+  int rc;
+
+  rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, &bReplace, &bRetry);
+  if( rc==SQLITE_OK ){
+    /* If the bRetry flag is set, the change has not been applied due to an
+    ** SQLITE_CHANGESET_DATA problem (i.e. this is an UPDATE or DELETE and
+    ** a row with the correct PK is present in the db, but one or more other
+    ** fields do not contain the expected values) and the conflict handler 
+    ** returned SQLITE_CHANGESET_REPLACE. In this case retry the operation,
+    ** but pass NULL as the final argument so that sessionApplyOneOp() ignores
+    ** the SQLITE_CHANGESET_DATA problem.  */
+    if( bRetry ){
+      assert( pIter->op==SQLITE_UPDATE || pIter->op==SQLITE_DELETE );
+      rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0);
+    }
+
+    /* If the bReplace flag is set, the change is an INSERT that has not
+    ** been performed because the database already contains a row with the
+    ** specified primary key and the conflict handler returned
+    ** SQLITE_CHANGESET_REPLACE. In this case remove the conflicting row
+    ** before reattempting the INSERT.  */
+    else if( bReplace ){
+      assert( pIter->op==SQLITE_INSERT );
+      rc = sqlite3_exec(db, "SAVEPOINT replace_op", 0, 0, 0);
+      if( rc==SQLITE_OK ){
+        rc = sessionBindRow(pIter, 
+            sqlite3changeset_new, pApply->nCol, pApply->abPK, pApply->pDelete);
+        sqlite3_bind_int(pApply->pDelete, pApply->nCol+1, 1);
+      }
+      if( rc==SQLITE_OK ){
+        sqlite3_step(pApply->pDelete);
+        rc = sqlite3_reset(pApply->pDelete);
+      }
+      if( rc==SQLITE_OK ){
+        rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0);
+      }
+      if( rc==SQLITE_OK ){
+        rc = sqlite3_exec(db, "RELEASE replace_op", 0, 0, 0);
+      }
+    }
   }
-  if( pParse->oom ) return 0;
-  return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr);
-}
 
-/*
-** Return the text of a syntax error message on a JSON path.  Space is
-** obtained from sqlite3_malloc().
-*/
-static char *jsonPathSyntaxError(const char *zErr){
-  return sqlite3_mprintf("JSON path error near '%q'", zErr);
+  return rc;
 }
 
 /*
-** Do a node lookup using zPath.  Return a pointer to the node on success.
-** Return NULL if not found or if there is an error.
-**
-** On an error, write an error message into pCtx and increment the
-** pParse->nErr counter.
-**
-** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if
-** nodes are appended.
+** Retry the changes accumulated in the pApply->constraints buffer.
 */
-static JsonNode *jsonLookup(
-  JsonParse *pParse,      /* The JSON to search */
-  const char *zPath,      /* The path to search */
-  int *pApnd,             /* Append nodes to complete path if not NULL */
-  sqlite3_context *pCtx   /* Report errors here, if not NULL */
+static int sessionRetryConstraints(
+  sqlite3 *db, 
+  int bPatchset,
+  const char *zTab,
+  SessionApplyCtx *pApply,
+  int(*xConflict)(void*, int, sqlite3_changeset_iter*),
+  void *pCtx                      /* First argument passed to xConflict */
 ){
-  const char *zErr = 0;
-  JsonNode *pNode = 0;
-  char *zMsg;
+  int rc = SQLITE_OK;
 
-  if( zPath==0 ) return 0;
-  if( zPath[0]!='$' ){
-    zErr = zPath;
-    goto lookup_err;
-  }
-  zPath++;
-  pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr);
-  if( zErr==0 ) return pNode;
+  while( pApply->constraints.nBuf ){
+    sqlite3_changeset_iter *pIter2 = 0;
+    SessionBuffer cons = pApply->constraints;
+    memset(&pApply->constraints, 0, sizeof(SessionBuffer));
 
-lookup_err:
-  pParse->nErr++;
-  assert( zErr!=0 && pCtx!=0 );
-  zMsg = jsonPathSyntaxError(zErr);
-  if( zMsg ){
-    sqlite3_result_error(pCtx, zMsg, -1);
-    sqlite3_free(zMsg);
-  }else{
-    sqlite3_result_error_nomem(pCtx);
+    rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf);
+    if( rc==SQLITE_OK ){
+      int nByte = 2*pApply->nCol*sizeof(sqlite3_value*);
+      int rc2;
+      pIter2->bPatchset = bPatchset;
+      pIter2->zTab = (char*)zTab;
+      pIter2->nCol = pApply->nCol;
+      pIter2->abPK = pApply->abPK;
+      sessionBufferGrow(&pIter2->tblhdr, nByte, &rc);
+      pIter2->apValue = (sqlite3_value**)pIter2->tblhdr.aBuf;
+      if( rc==SQLITE_OK ) memset(pIter2->apValue, 0, nByte);
+
+      while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter2) ){
+        rc = sessionApplyOneWithRetry(db, pIter2, pApply, xConflict, pCtx);
+      }
+
+      rc2 = sqlite3changeset_finalize(pIter2);
+      if( rc==SQLITE_OK ) rc = rc2;
+    }
+    assert( pApply->bDeferConstraints || pApply->constraints.nBuf==0 );
+
+    sqlite3_free(cons.aBuf);
+    if( rc!=SQLITE_OK ) break;
+    if( pApply->constraints.nBuf>=cons.nBuf ){
+      /* No progress was made on the last round. */
+      pApply->bDeferConstraints = 0;
+    }
   }
-  return 0;
-}
 
+  return rc;
+}
 
 /*
-** Report the wrong number of arguments for json_insert(), json_replace()
-** or json_set().
+** Argument pIter is a changeset iterator that has been initialized, but
+** not yet passed to sqlite3changeset_next(). This function applies the 
+** changeset to the main database attached to handle "db". The supplied
+** conflict handler callback is invoked to resolve any conflicts encountered
+** while applying the change.
 */
-static void jsonWrongNumArgs(
-  sqlite3_context *pCtx,
-  const char *zFuncName
+static int sessionChangesetApply(
+  sqlite3 *db,                    /* Apply change to "main" db of this handle */
+  sqlite3_changeset_iter *pIter,  /* Changeset to apply */
+  int(*xFilter)(
+    void *pCtx,                   /* Copy of sixth arg to _apply() */
+    const char *zTab              /* Table name */
+  ),
+  int(*xConflict)(
+    void *pCtx,                   /* Copy of fifth 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 */
+  void **ppRebase, int *pnRebase, /* OUT: Rebase information */
+  int flags                       /* SESSION_APPLY_XXX flags */
 ){
-  char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments",
-                               zFuncName);
-  sqlite3_result_error(pCtx, zMsg, -1);
-  sqlite3_free(zMsg);     
-}
+  int schemaMismatch = 0;
+  int rc = SQLITE_OK;             /* Return code */
+  const char *zTab = 0;           /* Name of current table */
+  int nTab = 0;                   /* Result of sqlite3Strlen30(zTab) */
+  SessionApplyCtx sApply;         /* changeset_apply() context object */
+  int bPatchset;
 
-/*
-** Mark all NULL entries in the Object passed in as JNODE_REMOVE.
-*/
-static void jsonRemoveAllNulls(JsonNode *pNode){
-  int i, n;
-  assert( pNode->eType==JSON_OBJECT );
-  n = pNode->n;
-  for(i=2; i<=n; i += jsonNodeSize(&pNode[i])+1){
-    switch( pNode[i].eType ){
-      case JSON_NULL:
-        pNode[i].jnFlags |= JNODE_REMOVE;
-        break;
-      case JSON_OBJECT:
-        jsonRemoveAllNulls(&pNode[i]);
-        break;
+  assert( xConflict!=0 );
+
+  pIter->in.bNoDiscard = 1;
+  memset(&sApply, 0, sizeof(sApply));
+  sqlite3_mutex_enter(sqlite3_db_mutex(db));
+  if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
+    rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
+  }
+  if( rc==SQLITE_OK ){
+    rc = sqlite3_exec(db, "PRAGMA defer_foreign_keys = 1", 0, 0, 0);
+  }
+  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter) ){
+    int nCol;
+    int op;
+    const char *zNew;
+    
+    sqlite3changeset_op(pIter, &zNew, &nCol, &op, 0);
+
+    if( zTab==0 || sqlite3_strnicmp(zNew, zTab, nTab+1) ){
+      u8 *abPK;
+
+      rc = sessionRetryConstraints(
+          db, pIter->bPatchset, zTab, &sApply, xConflict, pCtx
+      );
+      if( rc!=SQLITE_OK ) break;
+
+      sqlite3_free((char*)sApply.azCol);  /* cast works around VC++ bug */
+      sqlite3_finalize(sApply.pDelete);
+      sqlite3_finalize(sApply.pUpdate); 
+      sqlite3_finalize(sApply.pInsert);
+      sqlite3_finalize(sApply.pSelect);
+      sApply.db = db;
+      sApply.pDelete = 0;
+      sApply.pUpdate = 0;
+      sApply.pInsert = 0;
+      sApply.pSelect = 0;
+      sApply.nCol = 0;
+      sApply.azCol = 0;
+      sApply.abPK = 0;
+      sApply.bStat1 = 0;
+      sApply.bDeferConstraints = 1;
+      sApply.bRebaseStarted = 0;
+      memset(&sApply.constraints, 0, sizeof(SessionBuffer));
+
+      /* If an xFilter() callback was specified, invoke it now. If the 
+      ** xFilter callback returns zero, skip this table. If it returns
+      ** non-zero, proceed. */
+      schemaMismatch = (xFilter && (0==xFilter(pCtx, zNew)));
+      if( schemaMismatch ){
+        zTab = sqlite3_mprintf("%s", zNew);
+        if( zTab==0 ){
+          rc = SQLITE_NOMEM;
+          break;
+        }
+        nTab = (int)strlen(zTab);
+        sApply.azCol = (const char **)zTab;
+      }else{
+        int nMinCol = 0;
+        int i;
+
+        sqlite3changeset_pk(pIter, &abPK, 0);
+        rc = sessionTableInfo(
+            db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK
+        );
+        if( rc!=SQLITE_OK ) break;
+        for(i=0; i<sApply.nCol; i++){
+          if( sApply.abPK[i] ) nMinCol = i+1;
+        }
+  
+        if( sApply.nCol==0 ){
+          schemaMismatch = 1;
+          sqlite3_log(SQLITE_SCHEMA, 
+              "sqlite3changeset_apply(): no such table: %s", zTab
+          );
+        }
+        else if( sApply.nCol<nCol ){
+          schemaMismatch = 1;
+          sqlite3_log(SQLITE_SCHEMA, 
+              "sqlite3changeset_apply(): table %s has %d columns, "
+              "expected %d or more", 
+              zTab, sApply.nCol, nCol
+          );
+        }
+        else if( nCol<nMinCol || memcmp(sApply.abPK, abPK, nCol)!=0 ){
+          schemaMismatch = 1;
+          sqlite3_log(SQLITE_SCHEMA, "sqlite3changeset_apply(): "
+              "primary key mismatch for table %s", zTab
+          );
+        }
+        else{
+          sApply.nCol = nCol;
+          if( 0==sqlite3_stricmp(zTab, "sqlite_stat1") ){
+            if( (rc = sessionStat1Sql(db, &sApply) ) ){
+              break;
+            }
+            sApply.bStat1 = 1;
+          }else{
+            if((rc = sessionSelectRow(db, zTab, &sApply))
+                || (rc = sessionUpdateRow(db, zTab, &sApply))
+                || (rc = sessionDeleteRow(db, zTab, &sApply))
+                || (rc = sessionInsertRow(db, zTab, &sApply))
+              ){
+              break;
+            }
+            sApply.bStat1 = 0;
+          }
+        }
+        nTab = sqlite3Strlen30(zTab);
+      }
     }
+
+    /* If there is a schema mismatch on the current table, proceed to the
+    ** next change. A log message has already been issued. */
+    if( schemaMismatch ) continue;
+
+    rc = sessionApplyOneWithRetry(db, pIter, &sApply, xConflict, pCtx);
   }
-}
 
+  bPatchset = pIter->bPatchset;
+  if( rc==SQLITE_OK ){
+    rc = sqlite3changeset_finalize(pIter);
+  }else{
+    sqlite3changeset_finalize(pIter);
+  }
 
-/****************************************************************************
-** SQL functions used for testing and debugging
-****************************************************************************/
+  if( rc==SQLITE_OK ){
+    rc = sessionRetryConstraints(db, bPatchset, zTab, &sApply, xConflict, pCtx);
+  }
 
-#ifdef SQLITE_DEBUG
-/*
-** The json_parse(JSON) function returns a string which describes
-** a parse of the JSON provided.  Or it returns NULL if JSON is not
-** well-formed.
-*/
-static void jsonParseFunc(
-  sqlite3_context *ctx,
-  int argc,
-  sqlite3_value **argv
-){
-  JsonString s;       /* Output string - not real JSON */
-  JsonParse x;        /* The parse */
-  u32 i;
+  if( rc==SQLITE_OK ){
+    int nFk, notUsed;
+    sqlite3_db_status(db, SQLITE_DBSTATUS_DEFERRED_FKS, &nFk, &notUsed, 0);
+    if( nFk!=0 ){
+      int res = SQLITE_CHANGESET_ABORT;
+      sqlite3_changeset_iter sIter;
+      memset(&sIter, 0, sizeof(sIter));
+      sIter.nCol = nFk;
+      res = xConflict(pCtx, SQLITE_CHANGESET_FOREIGN_KEY, &sIter);
+      if( res!=SQLITE_CHANGESET_OMIT ){
+        rc = SQLITE_CONSTRAINT;
+      }
+    }
+  }
+  sqlite3_exec(db, "PRAGMA defer_foreign_keys = 0", 0, 0, 0);
 
-  assert( argc==1 );
-  if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
-  jsonParseFindParents(&x);
-  jsonInit(&s, ctx);
-  for(i=0; i<x.nNode; i++){
-    const char *zType;
-    if( x.aNode[i].jnFlags & JNODE_LABEL ){
-      assert( x.aNode[i].eType==JSON_STRING );
-      zType = "label";
+  if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
+    if( rc==SQLITE_OK ){
+      rc = sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
     }else{
-      zType = jsonType[x.aNode[i].eType];
-    }
-    jsonPrintf(100, &s,"node %3u: %7s n=%-4d up=%-4d",
-               i, zType, x.aNode[i].n, x.aUp[i]);
-    if( x.aNode[i].u.zJContent!=0 ){
-      jsonAppendRaw(&s, " ", 1);
-      jsonAppendRaw(&s, x.aNode[i].u.zJContent, x.aNode[i].n);
+      sqlite3_exec(db, "ROLLBACK TO changeset_apply", 0, 0, 0);
+      sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
     }
-    jsonAppendRaw(&s, "\n", 1);
   }
-  jsonParseReset(&x);
-  jsonResult(&s);
+
+  if( rc==SQLITE_OK && bPatchset==0 && ppRebase && pnRebase ){
+    *ppRebase = (void*)sApply.rebase.aBuf;
+    *pnRebase = sApply.rebase.nBuf;
+    sApply.rebase.aBuf = 0;
+  }
+  sqlite3_finalize(sApply.pInsert);
+  sqlite3_finalize(sApply.pDelete);
+  sqlite3_finalize(sApply.pUpdate);
+  sqlite3_finalize(sApply.pSelect);
+  sqlite3_free((char*)sApply.azCol);  /* cast works around VC++ bug */
+  sqlite3_free((char*)sApply.constraints.aBuf);
+  sqlite3_free((char*)sApply.rebase.aBuf);
+  sqlite3_mutex_leave(sqlite3_db_mutex(db));
+  return rc;
 }
 
 /*
-** The json_test1(JSON) function return true (1) if the input is JSON
-** text generated by another json function.  It returns (0) if the input
-** is not known to be JSON.
+** Apply the changeset passed via pChangeset/nChangeset to the main 
+** database attached to handle "db".
 */
-static void jsonTest1Func(
-  sqlite3_context *ctx,
-  int argc,
-  sqlite3_value **argv
+SQLITE_API int sqlite3changeset_apply_v2(
+  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 */
+  void **ppRebase, int *pnRebase,
+  int flags
 ){
-  UNUSED_PARAM(argc);
-  sqlite3_result_int(ctx, sqlite3_value_subtype(argv[0])==JSON_SUBTYPE);
+  sqlite3_changeset_iter *pIter;  /* Iterator to skip through changeset */  
+  int rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
+  if( rc==SQLITE_OK ){
+    rc = sessionChangesetApply(
+        db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
+    );
+  }
+  return rc;
 }
-#endif /* SQLITE_DEBUG */
-
-/****************************************************************************
-** Scalar SQL function implementations
-****************************************************************************/
 
 /*
-** Implementation of the json_QUOTE(VALUE) function.  Return a JSON value
-** corresponding to the SQL value input.  Mostly this means putting 
-** double-quotes around strings and returning the unquoted string "null"
-** when given a NULL input.
+** Apply the changeset passed via pChangeset/nChangeset to the main database
+** attached to handle "db". Invoke the supplied conflict handler callback
+** to resolve any conflicts encountered while applying the change.
 */
-static void jsonQuoteFunc(
-  sqlite3_context *ctx,
-  int argc,
-  sqlite3_value **argv
+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 fifth 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 */
 ){
-  JsonString jx;
-  UNUSED_PARAM(argc);
-
-  jsonInit(&jx, ctx);
-  jsonAppendValue(&jx, argv[0]);
-  jsonResult(&jx);
-  sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+  return sqlite3changeset_apply_v2(
+      db, nChangeset, pChangeset, xFilter, xConflict, pCtx, 0, 0, 0
+  );
 }
 
 /*
-** Implementation of the json_array(VALUE,...) function.  Return a JSON
-** array that contains all values given in arguments.  Or if any argument
-** is a BLOB, throw an error.
+** Apply the changeset passed via xInput/pIn to the main database
+** attached to handle "db". Invoke the supplied conflict handler callback
+** to resolve any conflicts encountered while applying the change.
 */
-static void jsonArrayFunc(
-  sqlite3_context *ctx,
-  int argc,
-  sqlite3_value **argv
+SQLITE_API int sqlite3changeset_apply_v2_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 */
+  void **ppRebase, int *pnRebase,
+  int flags
 ){
-  int i;
-  JsonString jx;
-
-  jsonInit(&jx, ctx);
-  jsonAppendChar(&jx, '[');
-  for(i=0; i<argc; i++){
-    jsonAppendSeparator(&jx);
-    jsonAppendValue(&jx, argv[i]);
+  sqlite3_changeset_iter *pIter;  /* Iterator to skip through changeset */  
+  int rc = sqlite3changeset_start_strm(&pIter, xInput, pIn);
+  if( rc==SQLITE_OK ){
+    rc = sessionChangesetApply(
+        db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
+    );
   }
-  jsonAppendChar(&jx, ']');
-  jsonResult(&jx);
-  sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+  return rc;
+}
+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 */
+){
+  return sqlite3changeset_apply_v2_strm(
+      db, xInput, pIn, xFilter, xConflict, pCtx, 0, 0, 0
+  );
 }
-
 
 /*
-** json_array_length(JSON)
-** json_array_length(JSON, PATH)
-**
-** Return the number of elements in the top-level JSON array.  
-** Return 0 if the input is not a well-formed JSON array.
+** sqlite3_changegroup handle.
 */
-static void jsonArrayLengthFunc(
-  sqlite3_context *ctx,
-  int argc,
-  sqlite3_value **argv
-){
-  JsonParse *p;          /* The parse */
-  sqlite3_int64 n = 0;
-  u32 i;
-  JsonNode *pNode;
-
-  p = jsonParseCached(ctx, argv);
-  if( p==0 ) return;
-  assert( p->nNode );
-  if( argc==2 ){
-    const char *zPath = (const char*)sqlite3_value_text(argv[1]);
-    pNode = jsonLookup(p, zPath, 0, ctx);
-  }else{
-    pNode = p->aNode;
-  }
-  if( pNode==0 ){
-    return;
-  }
-  if( pNode->eType==JSON_ARRAY ){
-    assert( (pNode->jnFlags & JNODE_APPEND)==0 );
-    for(i=1; i<=pNode->n; n++){
-      i += jsonNodeSize(&pNode[i]);
-    }
-  }
-  sqlite3_result_int64(ctx, n);
-}
+struct sqlite3_changegroup {
+  int rc;                         /* Error code */
+  int bPatch;                     /* True to accumulate patchsets */
+  SessionTable *pList;            /* List of tables in current patch */
+};
 
 /*
-** json_extract(JSON, PATH, ...)
-**
-** Return the element described by PATH.  Return NULL if there is no
-** PATH element.  If there are multiple PATHs, then return a JSON array
-** with the result from each path.  Throw an error if the JSON or any PATH
-** is malformed.
+** This function is called to merge two changes to the same row together as
+** part of an sqlite3changeset_concat() operation. A new change object is
+** allocated and a pointer to it stored in *ppNew.
 */
-static void jsonExtractFunc(
-  sqlite3_context *ctx,
-  int argc,
-  sqlite3_value **argv
+static int sessionChangeMerge(
+  SessionTable *pTab,             /* Table structure */
+  int bRebase,                    /* True for a rebase hash-table */
+  int bPatchset,                  /* True for patchsets */
+  SessionChange *pExist,          /* Existing change */
+  int op2,                        /* Second change operation */
+  int bIndirect,                  /* True if second change is indirect */
+  u8 *aRec,                       /* Second change record */
+  int nRec,                       /* Number of bytes in aRec */
+  SessionChange **ppNew           /* OUT: Merged change */
 ){
-  JsonParse *p;          /* The parse */
-  JsonNode *pNode;
-  const char *zPath;
-  JsonString jx;
-  int i;
+  SessionChange *pNew = 0;
+  int rc = SQLITE_OK;
 
-  if( argc<2 ) return;
-  p = jsonParseCached(ctx, argv);
-  if( p==0 ) return;
-  jsonInit(&jx, ctx);
-  jsonAppendChar(&jx, '[');
-  for(i=1; i<argc; i++){
-    zPath = (const char*)sqlite3_value_text(argv[i]);
-    pNode = jsonLookup(p, zPath, 0, ctx);
-    if( p->nErr ) break;
-    if( argc>2 ){
-      jsonAppendSeparator(&jx);
-      if( pNode ){
-        jsonRenderNode(pNode, &jx, 0);
+  if( !pExist ){
+    pNew = (SessionChange *)sqlite3_malloc(sizeof(SessionChange) + nRec);
+    if( !pNew ){
+      return SQLITE_NOMEM;
+    }
+    memset(pNew, 0, sizeof(SessionChange));
+    pNew->op = op2;
+    pNew->bIndirect = bIndirect;
+    pNew->aRecord = (u8*)&pNew[1];
+    if( bIndirect==0 || bRebase==0 ){
+      pNew->nRecord = nRec;
+      memcpy(pNew->aRecord, aRec, nRec);
+    }else{
+      int i;
+      u8 *pIn = aRec;
+      u8 *pOut = pNew->aRecord;
+      for(i=0; i<pTab->nCol; i++){
+        int nIn = sessionSerialLen(pIn);
+        if( *pIn==0 ){
+          *pOut++ = 0;
+        }else if( pTab->abPK[i]==0 ){
+          *pOut++ = 0xFF;
+        }else{
+          memcpy(pOut, pIn, nIn);
+          pOut += nIn;
+        }
+        pIn += nIn;
+      }
+      pNew->nRecord = pOut - pNew->aRecord;
+    }
+  }else if( bRebase ){
+    if( pExist->op==SQLITE_DELETE && pExist->bIndirect ){
+      *ppNew = pExist;
+    }else{
+      int nByte = nRec + pExist->nRecord + sizeof(SessionChange);
+      pNew = (SessionChange*)sqlite3_malloc(nByte);
+      if( pNew==0 ){
+        rc = SQLITE_NOMEM;
       }else{
-        jsonAppendRaw(&jx, "null", 4);
+        int i;
+        u8 *a1 = pExist->aRecord;
+        u8 *a2 = aRec;
+        u8 *pOut;
+
+        memset(pNew, 0, nByte);
+        pNew->bIndirect = bIndirect || pExist->bIndirect;
+        pNew->op = op2;
+        pOut = pNew->aRecord = (u8*)&pNew[1];
+
+        for(i=0; i<pTab->nCol; i++){
+          int n1 = sessionSerialLen(a1);
+          int n2 = sessionSerialLen(a2);
+          if( *a1==0xFF || (pTab->abPK[i]==0 && bIndirect) ){
+            *pOut++ = 0xFF;
+          }else if( *a2==0 ){
+            memcpy(pOut, a1, n1);
+            pOut += n1;
+          }else{
+            memcpy(pOut, a2, n2);
+            pOut += n2;
+          }
+          a1 += n1;
+          a2 += n2;
+        }
+        pNew->nRecord = pOut - pNew->aRecord;
       }
-    }else if( pNode ){
-      jsonReturn(pNode, ctx, 0);
+      sqlite3_free(pExist);
     }
-  }
-  if( argc>2 && i==argc ){
-    jsonAppendChar(&jx, ']');
-    jsonResult(&jx);
-    sqlite3_result_subtype(ctx, JSON_SUBTYPE);
-  }
-  jsonReset(&jx);
-}
+  }else{
+    int op1 = pExist->op;
 
-/* This is the RFC 7396 MergePatch algorithm.
-*/
-static JsonNode *jsonMergePatch(
-  JsonParse *pParse,   /* The JSON parser that contains the TARGET */
-  u32 iTarget,         /* Node of the TARGET in pParse */
-  JsonNode *pPatch     /* The PATCH */
-){
-  u32 i, j;
-  u32 iRoot;
-  JsonNode *pTarget;
-  if( pPatch->eType!=JSON_OBJECT ){
-    return pPatch;
-  }
-  assert( iTarget>=0 && iTarget<pParse->nNode );
-  pTarget = &pParse->aNode[iTarget];
-  assert( (pPatch->jnFlags & JNODE_APPEND)==0 );
-  if( pTarget->eType!=JSON_OBJECT ){
-    jsonRemoveAllNulls(pPatch);
-    return pPatch;
-  }
-  iRoot = iTarget;
-  for(i=1; i<pPatch->n; i += jsonNodeSize(&pPatch[i+1])+1){
-    u32 nKey;
-    const char *zKey;
-    assert( pPatch[i].eType==JSON_STRING );
-    assert( pPatch[i].jnFlags & JNODE_LABEL );
-    nKey = pPatch[i].n;
-    zKey = pPatch[i].u.zJContent;
-    assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
-    for(j=1; j<pTarget->n; j += jsonNodeSize(&pTarget[j+1])+1 ){
-      assert( pTarget[j].eType==JSON_STRING );
-      assert( pTarget[j].jnFlags & JNODE_LABEL );
-      assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
-      if( pTarget[j].n==nKey && strncmp(pTarget[j].u.zJContent,zKey,nKey)==0 ){
-        if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_PATCH) ) break;
-        if( pPatch[i+1].eType==JSON_NULL ){
-          pTarget[j+1].jnFlags |= JNODE_REMOVE;
+    /* 
+    **   op1=INSERT, op2=INSERT      ->      Unsupported. Discard op2.
+    **   op1=INSERT, op2=UPDATE      ->      INSERT.
+    **   op1=INSERT, op2=DELETE      ->      (none)
+    **
+    **   op1=UPDATE, op2=INSERT      ->      Unsupported. Discard op2.
+    **   op1=UPDATE, op2=UPDATE      ->      UPDATE.
+    **   op1=UPDATE, op2=DELETE      ->      DELETE.
+    **
+    **   op1=DELETE, op2=INSERT      ->      UPDATE.
+    **   op1=DELETE, op2=UPDATE      ->      Unsupported. Discard op2.
+    **   op1=DELETE, op2=DELETE      ->      Unsupported. Discard op2.
+    */   
+    if( (op1==SQLITE_INSERT && op2==SQLITE_INSERT)
+     || (op1==SQLITE_UPDATE && op2==SQLITE_INSERT)
+     || (op1==SQLITE_DELETE && op2==SQLITE_UPDATE)
+     || (op1==SQLITE_DELETE && op2==SQLITE_DELETE)
+    ){
+      pNew = pExist;
+    }else if( op1==SQLITE_INSERT && op2==SQLITE_DELETE ){
+      sqlite3_free(pExist);
+      assert( pNew==0 );
+    }else{
+      u8 *aExist = pExist->aRecord;
+      int nByte;
+      u8 *aCsr;
+
+      /* Allocate a new SessionChange object. Ensure that the aRecord[]
+      ** buffer of the new object is large enough to hold any record that
+      ** may be generated by combining the input records.  */
+      nByte = sizeof(SessionChange) + pExist->nRecord + nRec;
+      pNew = (SessionChange *)sqlite3_malloc(nByte);
+      if( !pNew ){
+        sqlite3_free(pExist);
+        return SQLITE_NOMEM;
+      }
+      memset(pNew, 0, sizeof(SessionChange));
+      pNew->bIndirect = (bIndirect && pExist->bIndirect);
+      aCsr = pNew->aRecord = (u8 *)&pNew[1];
+
+      if( op1==SQLITE_INSERT ){             /* INSERT + UPDATE */
+        u8 *a1 = aRec;
+        assert( op2==SQLITE_UPDATE );
+        pNew->op = SQLITE_INSERT;
+        if( bPatchset==0 ) sessionSkipRecord(&a1, pTab->nCol);
+        sessionMergeRecord(&aCsr, pTab->nCol, aExist, a1);
+      }else if( op1==SQLITE_DELETE ){       /* DELETE + INSERT */
+        assert( op2==SQLITE_INSERT );
+        pNew->op = SQLITE_UPDATE;
+        if( bPatchset ){
+          memcpy(aCsr, aRec, nRec);
+          aCsr += nRec;
         }else{
-          JsonNode *pNew = jsonMergePatch(pParse, iTarget+j+1, &pPatch[i+1]);
-          if( pNew==0 ) return 0;
-          pTarget = &pParse->aNode[iTarget];
-          if( pNew!=&pTarget[j+1] ){
-            pTarget[j+1].u.pPatch = pNew;
-            pTarget[j+1].jnFlags |= JNODE_PATCH;
+          if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aExist, 0,aRec,0) ){
+            sqlite3_free(pNew);
+            pNew = 0;
           }
         }
-        break;
+      }else if( op2==SQLITE_UPDATE ){       /* UPDATE + UPDATE */
+        u8 *a1 = aExist;
+        u8 *a2 = aRec;
+        assert( op1==SQLITE_UPDATE );
+        if( bPatchset==0 ){
+          sessionSkipRecord(&a1, pTab->nCol);
+          sessionSkipRecord(&a2, pTab->nCol);
+        }
+        pNew->op = SQLITE_UPDATE;
+        if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aRec, aExist,a1,a2) ){
+          sqlite3_free(pNew);
+          pNew = 0;
+        }
+      }else{                                /* UPDATE + DELETE */
+        assert( op1==SQLITE_UPDATE && op2==SQLITE_DELETE );
+        pNew->op = SQLITE_DELETE;
+        if( bPatchset ){
+          memcpy(aCsr, aRec, nRec);
+          aCsr += nRec;
+        }else{
+          sessionMergeRecord(&aCsr, pTab->nCol, aRec, aExist);
+        }
       }
-    }
-    if( j>=pTarget->n && pPatch[i+1].eType!=JSON_NULL ){
-      int iStart, iPatch;
-      iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
-      jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
-      iPatch = jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
-      if( pParse->oom ) return 0;
-      jsonRemoveAllNulls(pPatch);
-      pTarget = &pParse->aNode[iTarget];
-      pParse->aNode[iRoot].jnFlags |= JNODE_APPEND;
-      pParse->aNode[iRoot].u.iAppend = iStart - iRoot;
-      iRoot = iStart;
-      pParse->aNode[iPatch].jnFlags |= JNODE_PATCH;
-      pParse->aNode[iPatch].u.pPatch = &pPatch[i+1];
+
+      if( pNew ){
+        pNew->nRecord = (int)(aCsr - pNew->aRecord);
+      }
+      sqlite3_free(pExist);
     }
   }
-  return pTarget;
+
+  *ppNew = pNew;
+  return rc;
 }
 
 /*
-** Implementation of the json_mergepatch(JSON1,JSON2) function.  Return a JSON
-** object that is the result of running the RFC 7396 MergePatch() algorithm
-** on the two arguments.
+** Add all changes in the changeset traversed by the iterator passed as
+** the first argument to the changegroup hash tables.
 */
-static void jsonPatchFunc(
-  sqlite3_context *ctx,
-  int argc,
-  sqlite3_value **argv
+static int sessionChangesetToHash(
+  sqlite3_changeset_iter *pIter,   /* Iterator to read from */
+  sqlite3_changegroup *pGrp,       /* Changegroup object to add changeset to */
+  int bRebase                      /* True if hash table is for rebasing */
 ){
-  JsonParse x;     /* The JSON that is being patched */
-  JsonParse y;     /* The patch */
-  JsonNode *pResult;   /* The result of the merge */
+  u8 *aRec;
+  int nRec;
+  int rc = SQLITE_OK;
+  SessionTable *pTab = 0;
 
-  UNUSED_PARAM(argc);
-  if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
-  if( jsonParse(&y, ctx, (const char*)sqlite3_value_text(argv[1])) ){
-    jsonParseReset(&x);
-    return;
-  }
-  pResult = jsonMergePatch(&x, 0, y.aNode);
-  assert( pResult!=0 || x.oom );
-  if( pResult ){
-    jsonReturnJson(pResult, ctx, 0);
-  }else{
-    sqlite3_result_error_nomem(ctx);
-  }
-  jsonParseReset(&x);
-  jsonParseReset(&y);
-}
+  while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec, 0) ){
+    const char *zNew;
+    int nCol;
+    int op;
+    int iHash;
+    int bIndirect;
+    SessionChange *pChange;
+    SessionChange *pExist = 0;
+    SessionChange **pp;
 
+    if( pGrp->pList==0 ){
+      pGrp->bPatch = pIter->bPatchset;
+    }else if( pIter->bPatchset!=pGrp->bPatch ){
+      rc = SQLITE_ERROR;
+      break;
+    }
 
-/*
-** Implementation of the json_object(NAME,VALUE,...) function.  Return a JSON
-** object that contains all name/value given in arguments.  Or if any name
-** is not a string or if any value is a BLOB, throw an error.
-*/
-static void jsonObjectFunc(
-  sqlite3_context *ctx,
-  int argc,
-  sqlite3_value **argv
-){
-  int i;
-  JsonString jx;
-  const char *z;
-  u32 n;
+    sqlite3changeset_op(pIter, &zNew, &nCol, &op, &bIndirect);
+    if( !pTab || sqlite3_stricmp(zNew, pTab->zName) ){
+      /* Search the list for a matching table */
+      int nNew = (int)strlen(zNew);
+      u8 *abPK;
 
-  if( argc&1 ){
-    sqlite3_result_error(ctx, "json_object() requires an even number "
-                                  "of arguments", -1);
-    return;
-  }
-  jsonInit(&jx, ctx);
-  jsonAppendChar(&jx, '{');
-  for(i=0; i<argc; i+=2){
-    if( sqlite3_value_type(argv[i])!=SQLITE_TEXT ){
-      sqlite3_result_error(ctx, "json_object() labels must be TEXT", -1);
-      jsonReset(&jx);
-      return;
-    }
-    jsonAppendSeparator(&jx);
-    z = (const char*)sqlite3_value_text(argv[i]);
-    n = (u32)sqlite3_value_bytes(argv[i]);
-    jsonAppendString(&jx, z, n);
-    jsonAppendChar(&jx, ':');
-    jsonAppendValue(&jx, argv[i+1]);
-  }
-  jsonAppendChar(&jx, '}');
-  jsonResult(&jx);
-  sqlite3_result_subtype(ctx, JSON_SUBTYPE);
-}
+      sqlite3changeset_pk(pIter, &abPK, 0);
+      for(pTab = pGrp->pList; pTab; pTab=pTab->pNext){
+        if( 0==sqlite3_strnicmp(pTab->zName, zNew, nNew+1) ) break;
+      }
+      if( !pTab ){
+        SessionTable **ppTab;
 
+        pTab = sqlite3_malloc(sizeof(SessionTable) + nCol + nNew+1);
+        if( !pTab ){
+          rc = SQLITE_NOMEM;
+          break;
+        }
+        memset(pTab, 0, sizeof(SessionTable));
+        pTab->nCol = nCol;
+        pTab->abPK = (u8*)&pTab[1];
+        memcpy(pTab->abPK, abPK, nCol);
+        pTab->zName = (char*)&pTab->abPK[nCol];
+        memcpy(pTab->zName, zNew, nNew+1);
 
-/*
-** json_remove(JSON, PATH, ...)
-**
-** Remove the named elements from JSON and return the result.  malformed
-** JSON or PATH arguments result in an error.
-*/
-static void jsonRemoveFunc(
-  sqlite3_context *ctx,
-  int argc,
-  sqlite3_value **argv
-){
-  JsonParse x;          /* The parse */
-  JsonNode *pNode;
-  const char *zPath;
-  u32 i;
+        /* The new object must be linked on to the end of the list, not
+        ** simply added to the start of it. This is to ensure that the
+        ** tables within the output of sqlite3changegroup_output() are in 
+        ** the right order.  */
+        for(ppTab=&pGrp->pList; *ppTab; ppTab=&(*ppTab)->pNext);
+        *ppTab = pTab;
+      }else if( pTab->nCol!=nCol || memcmp(pTab->abPK, abPK, nCol) ){
+        rc = SQLITE_SCHEMA;
+        break;
+      }
+    }
 
-  if( argc<1 ) return;
-  if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
-  assert( x.nNode );
-  for(i=1; i<(u32)argc; i++){
-    zPath = (const char*)sqlite3_value_text(argv[i]);
-    if( zPath==0 ) goto remove_done;
-    pNode = jsonLookup(&x, zPath, 0, ctx);
-    if( x.nErr ) goto remove_done;
-    if( pNode ) pNode->jnFlags |= JNODE_REMOVE;
-  }
-  if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){
-    jsonReturnJson(x.aNode, ctx, 0);
-  }
-remove_done:
-  jsonParseReset(&x);
-}
+    if( sessionGrowHash(pIter->bPatchset, pTab) ){
+      rc = SQLITE_NOMEM;
+      break;
+    }
+    iHash = sessionChangeHash(
+        pTab, (pIter->bPatchset && op==SQLITE_DELETE), aRec, pTab->nChange
+    );
 
-/*
-** json_replace(JSON, PATH, VALUE, ...)
-**
-** Replace the value at PATH with VALUE.  If PATH does not already exist,
-** this routine is a no-op.  If JSON or PATH is malformed, throw an error.
-*/
-static void jsonReplaceFunc(
-  sqlite3_context *ctx,
-  int argc,
-  sqlite3_value **argv
-){
-  JsonParse x;          /* The parse */
-  JsonNode *pNode;
-  const char *zPath;
-  u32 i;
+    /* Search for existing entry. If found, remove it from the hash table. 
+    ** Code below may link it back in.
+    */
+    for(pp=&pTab->apChange[iHash]; *pp; pp=&(*pp)->pNext){
+      int bPkOnly1 = 0;
+      int bPkOnly2 = 0;
+      if( pIter->bPatchset ){
+        bPkOnly1 = (*pp)->op==SQLITE_DELETE;
+        bPkOnly2 = op==SQLITE_DELETE;
+      }
+      if( sessionChangeEqual(pTab, bPkOnly1, (*pp)->aRecord, bPkOnly2, aRec) ){
+        pExist = *pp;
+        *pp = (*pp)->pNext;
+        pTab->nEntry--;
+        break;
+      }
+    }
 
-  if( argc<1 ) return;
-  if( (argc&1)==0 ) {
-    jsonWrongNumArgs(ctx, "replace");
-    return;
-  }
-  if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
-  assert( x.nNode );
-  for(i=1; i<(u32)argc; i+=2){
-    zPath = (const char*)sqlite3_value_text(argv[i]);
-    pNode = jsonLookup(&x, zPath, 0, ctx);
-    if( x.nErr ) goto replace_err;
-    if( pNode ){
-      pNode->jnFlags |= (u8)JNODE_REPLACE;
-      pNode->u.iReplace = i + 1;
+    rc = sessionChangeMerge(pTab, bRebase, 
+        pIter->bPatchset, pExist, op, bIndirect, aRec, nRec, &pChange
+    );
+    if( rc ) break;
+    if( pChange ){
+      pChange->pNext = pTab->apChange[iHash];
+      pTab->apChange[iHash] = pChange;
+      pTab->nEntry++;
     }
   }
-  if( x.aNode[0].jnFlags & JNODE_REPLACE ){
-    sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
-  }else{
-    jsonReturnJson(x.aNode, ctx, argv);
-  }
-replace_err:
-  jsonParseReset(&x);
+
+  if( rc==SQLITE_OK ) rc = pIter->rc;
+  return rc;
 }
 
 /*
-** json_set(JSON, PATH, VALUE, ...)
+** Serialize a changeset (or patchset) based on all changesets (or patchsets)
+** added to the changegroup object passed as the first argument.
 **
-** Set the value at PATH to VALUE.  Create the PATH if it does not already
-** exist.  Overwrite existing values that do exist.
-** If JSON or PATH is malformed, throw an error.
+** If xOutput is not NULL, then the changeset/patchset is returned to the
+** user via one or more calls to xOutput, as with the other streaming
+** interfaces. 
 **
-** json_insert(JSON, PATH, VALUE, ...)
+** Or, if xOutput is NULL, then (*ppOut) is populated with a pointer to a
+** buffer containing the output changeset before this function returns. In
+** this case (*pnOut) is set to the size of the output buffer in bytes. It
+** is the responsibility of the caller to free the output buffer using
+** sqlite3_free() when it is no longer required.
 **
-** Create PATH and initialize it to VALUE.  If PATH already exists, this
-** routine is a no-op.  If JSON or PATH is malformed, throw an error.
+** If successful, SQLITE_OK is returned. Or, if an error occurs, an SQLite
+** error code. If an error occurs and xOutput is NULL, (*ppOut) and (*pnOut)
+** are both set to 0 before returning.
 */
-static void jsonSetFunc(
-  sqlite3_context *ctx,
-  int argc,
-  sqlite3_value **argv
+static int sessionChangegroupOutput(
+  sqlite3_changegroup *pGrp,
+  int (*xOutput)(void *pOut, const void *pData, int nData),
+  void *pOut,
+  int *pnOut,
+  void **ppOut
 ){
-  JsonParse x;          /* The parse */
-  JsonNode *pNode;
-  const char *zPath;
-  u32 i;
-  int bApnd;
-  int bIsSet = *(int*)sqlite3_user_data(ctx);
+  int rc = SQLITE_OK;
+  SessionBuffer buf = {0, 0, 0};
+  SessionTable *pTab;
+  assert( xOutput==0 || (ppOut==0 && pnOut==0) );
 
-  if( argc<1 ) return;
-  if( (argc&1)==0 ) {
-    jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert");
-    return;
-  }
-  if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
-  assert( x.nNode );
-  for(i=1; i<(u32)argc; i+=2){
-    zPath = (const char*)sqlite3_value_text(argv[i]);
-    bApnd = 0;
-    pNode = jsonLookup(&x, zPath, &bApnd, ctx);
-    if( x.oom ){
-      sqlite3_result_error_nomem(ctx);
-      goto jsonSetDone;
-    }else if( x.nErr ){
-      goto jsonSetDone;
-    }else if( pNode && (bApnd || bIsSet) ){
-      pNode->jnFlags |= (u8)JNODE_REPLACE;
-      pNode->u.iReplace = i + 1;
+  /* Create the serialized output changeset based on the contents of the
+  ** hash tables attached to the SessionTable objects in list p->pList. 
+  */
+  for(pTab=pGrp->pList; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
+    int i;
+    if( pTab->nEntry==0 ) continue;
+
+    sessionAppendTableHdr(&buf, pGrp->bPatch, pTab, &rc);
+    for(i=0; i<pTab->nChange; i++){
+      SessionChange *p;
+      for(p=pTab->apChange[i]; p; p=p->pNext){
+        sessionAppendByte(&buf, p->op, &rc);
+        sessionAppendByte(&buf, p->bIndirect, &rc);
+        sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc);
+      }
+    }
+
+    if( rc==SQLITE_OK && xOutput && buf.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){
+      rc = xOutput(pOut, buf.aBuf, buf.nBuf);
+      buf.nBuf = 0;
     }
   }
-  if( x.aNode[0].jnFlags & JNODE_REPLACE ){
-    sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
-  }else{
-    jsonReturnJson(x.aNode, ctx, argv);
+
+  if( rc==SQLITE_OK ){
+    if( xOutput ){
+      if( buf.nBuf>0 ) rc = xOutput(pOut, buf.aBuf, buf.nBuf);
+    }else{
+      *ppOut = buf.aBuf;
+      *pnOut = buf.nBuf;
+      buf.aBuf = 0;
+    }
   }
-jsonSetDone:
-  jsonParseReset(&x);
+  sqlite3_free(buf.aBuf);
+
+  return rc;
 }
 
 /*
-** json_type(JSON)
-** json_type(JSON, PATH)
-**
-** Return the top-level "type" of a JSON string.  Throw an error if
-** either the JSON or PATH inputs are not well-formed.
+** Allocate a new, empty, sqlite3_changegroup.
 */
-static void jsonTypeFunc(
-  sqlite3_context *ctx,
-  int argc,
-  sqlite3_value **argv
-){
-  JsonParse x;          /* The parse */
-  const char *zPath;
-  JsonNode *pNode;
-
-  if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
-  assert( x.nNode );
-  if( argc==2 ){
-    zPath = (const char*)sqlite3_value_text(argv[1]);
-    pNode = jsonLookup(&x, zPath, 0, ctx);
+SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp){
+  int rc = SQLITE_OK;             /* Return code */
+  sqlite3_changegroup *p;         /* New object */
+  p = (sqlite3_changegroup*)sqlite3_malloc(sizeof(sqlite3_changegroup));
+  if( p==0 ){
+    rc = SQLITE_NOMEM;
   }else{
-    pNode = x.aNode;
-  }
-  if( pNode ){
-    sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC);
+    memset(p, 0, sizeof(sqlite3_changegroup));
   }
-  jsonParseReset(&x);
+  *pp = p;
+  return rc;
 }
 
 /*
-** json_valid(JSON)
-**
-** Return 1 if JSON is a well-formed JSON string according to RFC-7159.
-** Return 0 otherwise.
+** Add the changeset currently stored in buffer pData, size nData bytes,
+** to changeset-group p.
 */
-static void jsonValidFunc(
-  sqlite3_context *ctx,
-  int argc,
-  sqlite3_value **argv
-){
-  JsonParse x;          /* The parse */
-  int rc = 0;
+SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup *pGrp, int nData, void *pData){
+  sqlite3_changeset_iter *pIter;  /* Iterator opened on pData/nData */
+  int rc;                         /* Return code */
 
-  UNUSED_PARAM(argc);
-  if( jsonParse(&x, 0, (const char*)sqlite3_value_text(argv[0]))==0 ){
-    rc = 1;
+  rc = sqlite3changeset_start(&pIter, nData, pData);
+  if( rc==SQLITE_OK ){
+    rc = sessionChangesetToHash(pIter, pGrp, 0);
   }
-  jsonParseReset(&x);
-  sqlite3_result_int(ctx, rc);
+  sqlite3changeset_finalize(pIter);
+  return rc;
 }
 
-
-/****************************************************************************
-** Aggregate SQL function implementations
-****************************************************************************/
 /*
-** json_group_array(VALUE)
-**
-** Return a JSON array composed of all values in the aggregate.
+** Obtain a buffer containing a changeset representing the concatenation
+** of all changesets added to the group so far.
 */
-static void jsonArrayStep(
-  sqlite3_context *ctx,
-  int argc,
-  sqlite3_value **argv
+SQLITE_API int sqlite3changegroup_output(
+    sqlite3_changegroup *pGrp,
+    int *pnData,
+    void **ppData
 ){
-  JsonString *pStr;
-  UNUSED_PARAM(argc);
-  pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
-  if( pStr ){
-    if( pStr->zBuf==0 ){
-      jsonInit(pStr, ctx);
-      jsonAppendChar(pStr, '[');
-    }else{
-      jsonAppendChar(pStr, ',');
-      pStr->pCtx = ctx;
-    }
-    jsonAppendValue(pStr, argv[0]);
-  }
-}
-static void jsonArrayFinal(sqlite3_context *ctx){
-  JsonString *pStr;
-  pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
-  if( pStr ){
-    pStr->pCtx = ctx;
-    jsonAppendChar(pStr, ']');
-    if( pStr->bErr ){
-      if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
-      assert( pStr->bStatic );
-    }else{
-      sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed,
-                          pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
-      pStr->bStatic = 1;
-    }
-  }else{
-    sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC);
-  }
-  sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+  return sessionChangegroupOutput(pGrp, 0, 0, pnData, ppData);
 }
 
 /*
-** json_group_obj(NAME,VALUE)
-**
-** Return a JSON object composed of all names and values in the aggregate.
+** Streaming versions of changegroup_add().
 */
-static void jsonObjectStep(
-  sqlite3_context *ctx,
-  int argc,
-  sqlite3_value **argv
-){
-  JsonString *pStr;
-  const char *z;
-  u32 n;
-  UNUSED_PARAM(argc);
-  pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
-  if( pStr ){
-    if( pStr->zBuf==0 ){
-      jsonInit(pStr, ctx);
-      jsonAppendChar(pStr, '{');
-    }else{
-      jsonAppendChar(pStr, ',');
-      pStr->pCtx = ctx;
-    }
-    z = (const char*)sqlite3_value_text(argv[0]);
-    n = (u32)sqlite3_value_bytes(argv[0]);
-    jsonAppendString(pStr, z, n);
-    jsonAppendChar(pStr, ':');
-    jsonAppendValue(pStr, argv[1]);
-  }
-}
-static void jsonObjectFinal(sqlite3_context *ctx){
-  JsonString *pStr;
-  pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
-  if( pStr ){
-    jsonAppendChar(pStr, '}');
-    if( pStr->bErr ){
-      if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
-      assert( pStr->bStatic );
-    }else{
-      sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed,
-                          pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
-      pStr->bStatic = 1;
-    }
-  }else{
-    sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC);
-  }
-  sqlite3_result_subtype(ctx, JSON_SUBTYPE);
-}
-
-
-#ifndef SQLITE_OMIT_VIRTUALTABLE
-/****************************************************************************
-** The json_each virtual table
-****************************************************************************/
-typedef struct JsonEachCursor JsonEachCursor;
-struct JsonEachCursor {
-  sqlite3_vtab_cursor base;  /* Base class - must be first */
-  u32 iRowid;                /* The rowid */
-  u32 iBegin;                /* The first node of the scan */
-  u32 i;                     /* Index in sParse.aNode[] of current row */
-  u32 iEnd;                  /* EOF when i equals or exceeds this value */
-  u8 eType;                  /* Type of top-level element */
-  u8 bRecursive;             /* True for json_tree().  False for json_each() */
-  char *zJson;               /* Input JSON */
-  char *zRoot;               /* Path by which to filter zJson */
-  JsonParse sParse;          /* Parse of the input JSON */
-};
-
-/* Constructor for the json_each virtual table */
-static int jsonEachConnect(
-  sqlite3 *db,
-  void *pAux,
-  int argc, const char *const*argv,
-  sqlite3_vtab **ppVtab,
-  char **pzErr
+SQLITE_API int sqlite3changegroup_add_strm(
+  sqlite3_changegroup *pGrp,
+  int (*xInput)(void *pIn, void *pData, int *pnData),
+  void *pIn
 ){
-  sqlite3_vtab *pNew;
-  int rc;
-
-/* Column numbers */
-#define JEACH_KEY     0
-#define JEACH_VALUE   1
-#define JEACH_TYPE    2
-#define JEACH_ATOM    3
-#define JEACH_ID      4
-#define JEACH_PARENT  5
-#define JEACH_FULLKEY 6
-#define JEACH_PATH    7
-#define JEACH_JSON    8
-#define JEACH_ROOT    9
+  sqlite3_changeset_iter *pIter;  /* Iterator opened on pData/nData */
+  int rc;                         /* Return code */
 
-  UNUSED_PARAM(pzErr);
-  UNUSED_PARAM(argv);
-  UNUSED_PARAM(argc);
-  UNUSED_PARAM(pAux);
-  rc = sqlite3_declare_vtab(db, 
-     "CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path,"
-                    "json HIDDEN,root HIDDEN)");
-  if( rc==SQLITE_OK ){
-    pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
-    if( pNew==0 ) return SQLITE_NOMEM;
-    memset(pNew, 0, sizeof(*pNew));
+  rc = sqlite3changeset_start_strm(&pIter, xInput, pIn);
+  if( rc==SQLITE_OK ){
+    rc = sessionChangesetToHash(pIter, pGrp, 0);
   }
+  sqlite3changeset_finalize(pIter);
   return rc;
 }
 
-/* destructor for json_each virtual table */
-static int jsonEachDisconnect(sqlite3_vtab *pVtab){
-  sqlite3_free(pVtab);
-  return SQLITE_OK;
+/*
+** Streaming versions of changegroup_output().
+*/
+SQLITE_API int sqlite3changegroup_output_strm(
+  sqlite3_changegroup *pGrp,
+  int (*xOutput)(void *pOut, const void *pData, int nData), 
+  void *pOut
+){
+  return sessionChangegroupOutput(pGrp, xOutput, pOut, 0, 0);
 }
 
-/* constructor for a JsonEachCursor object for json_each(). */
-static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
-  JsonEachCursor *pCur;
-
-  UNUSED_PARAM(p);
-  pCur = sqlite3_malloc( sizeof(*pCur) );
-  if( pCur==0 ) return SQLITE_NOMEM;
-  memset(pCur, 0, sizeof(*pCur));
-  *ppCursor = &pCur->base;
-  return SQLITE_OK;
+/*
+** Delete a changegroup object.
+*/
+SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){
+  if( pGrp ){
+    sessionDeleteTable(pGrp->pList);
+    sqlite3_free(pGrp);
+  }
 }
 
-/* constructor for a JsonEachCursor object for json_tree(). */
-static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
-  int rc = jsonEachOpenEach(p, ppCursor);
+/* 
+** Combine two changesets together.
+*/
+SQLITE_API int sqlite3changeset_concat(
+  int nLeft,                      /* Number of bytes in lhs input */
+  void *pLeft,                    /* Lhs input changeset */
+  int nRight                      /* Number of bytes in rhs input */,
+  void *pRight,                   /* Rhs input changeset */
+  int *pnOut,                     /* OUT: Number of bytes in output changeset */
+  void **ppOut                    /* OUT: changeset (left <concat> right) */
+){
+  sqlite3_changegroup *pGrp;
+  int rc;
+
+  rc = sqlite3changegroup_new(&pGrp);
   if( rc==SQLITE_OK ){
-    JsonEachCursor *pCur = (JsonEachCursor*)*ppCursor;
-    pCur->bRecursive = 1;
+    rc = sqlite3changegroup_add(pGrp, nLeft, pLeft);
   }
+  if( rc==SQLITE_OK ){
+    rc = sqlite3changegroup_add(pGrp, nRight, pRight);
+  }
+  if( rc==SQLITE_OK ){
+    rc = sqlite3changegroup_output(pGrp, pnOut, ppOut);
+  }
+  sqlite3changegroup_delete(pGrp);
+
   return rc;
 }
 
-/* Reset a JsonEachCursor back to its original state.  Free any memory
-** held. */
-static void jsonEachCursorReset(JsonEachCursor *p){
-  sqlite3_free(p->zJson);
-  sqlite3_free(p->zRoot);
-  jsonParseReset(&p->sParse);
-  p->iRowid = 0;
-  p->i = 0;
-  p->iEnd = 0;
-  p->eType = 0;
-  p->zJson = 0;
-  p->zRoot = 0;
-}
+/*
+** Streaming version of sqlite3changeset_concat().
+*/
+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
+){
+  sqlite3_changegroup *pGrp;
+  int rc;
 
-/* Destructor for a jsonEachCursor object */
-static int jsonEachClose(sqlite3_vtab_cursor *cur){
-  JsonEachCursor *p = (JsonEachCursor*)cur;
-  jsonEachCursorReset(p);
-  sqlite3_free(cur);
-  return SQLITE_OK;
-}
+  rc = sqlite3changegroup_new(&pGrp);
+  if( rc==SQLITE_OK ){
+    rc = sqlite3changegroup_add_strm(pGrp, xInputA, pInA);
+  }
+  if( rc==SQLITE_OK ){
+    rc = sqlite3changegroup_add_strm(pGrp, xInputB, pInB);
+  }
+  if( rc==SQLITE_OK ){
+    rc = sqlite3changegroup_output_strm(pGrp, xOutput, pOut);
+  }
+  sqlite3changegroup_delete(pGrp);
 
-/* Return TRUE if the jsonEachCursor object has been advanced off the end
-** of the JSON object */
-static int jsonEachEof(sqlite3_vtab_cursor *cur){
-  JsonEachCursor *p = (JsonEachCursor*)cur;
-  return p->i >= p->iEnd;
+  return rc;
 }
 
-/* Advance the cursor to the next element for json_tree() */
-static int jsonEachNext(sqlite3_vtab_cursor *cur){
-  JsonEachCursor *p = (JsonEachCursor*)cur;
-  if( p->bRecursive ){
-    if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++;
-    p->i++;
-    p->iRowid++;
-    if( p->i<p->iEnd ){
-      u32 iUp = p->sParse.aUp[p->i];
-      JsonNode *pUp = &p->sParse.aNode[iUp];
-      p->eType = pUp->eType;
-      if( pUp->eType==JSON_ARRAY ){
-        if( iUp==p->i-1 ){
-          pUp->u.iKey = 0;
-        }else{
-          pUp->u.iKey++;
-        }
-      }
-    }
-  }else{
-    switch( p->eType ){
-      case JSON_ARRAY: {
-        p->i += jsonNodeSize(&p->sParse.aNode[p->i]);
-        p->iRowid++;
-        break;
-      }
-      case JSON_OBJECT: {
-        p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]);
-        p->iRowid++;
-        break;
-      }
-      default: {
-        p->i = p->iEnd;
-        break;
+/*
+** Changeset rebaser handle.
+*/
+struct sqlite3_rebaser {
+  sqlite3_changegroup grp;        /* Hash table */
+};
+
+/*
+** Buffers a1 and a2 must both contain a sessions module record nCol
+** fields in size. This function appends an nCol sessions module 
+** record to buffer pBuf that is a copy of a1, except that for
+** each field that is undefined in a1[], swap in the field from a2[].
+*/
+static void sessionAppendRecordMerge(
+  SessionBuffer *pBuf,            /* Buffer to append to */
+  int nCol,                       /* Number of columns in each record */
+  u8 *a1, int n1,                 /* Record 1 */
+  u8 *a2, int n2,                 /* Record 2 */
+  int *pRc                        /* IN/OUT: error code */
+){
+  sessionBufferGrow(pBuf, n1+n2, pRc);
+  if( *pRc==SQLITE_OK ){
+    int i;
+    u8 *pOut = &pBuf->aBuf[pBuf->nBuf];
+    for(i=0; i<nCol; i++){
+      int nn1 = sessionSerialLen(a1);
+      int nn2 = sessionSerialLen(a2);
+      if( *a1==0 || *a1==0xFF ){
+        memcpy(pOut, a2, nn2);
+        pOut += nn2;
+      }else{
+        memcpy(pOut, a1, nn1);
+        pOut += nn1;
       }
+      a1 += nn1;
+      a2 += nn2;
     }
+
+    pBuf->nBuf = pOut-pBuf->aBuf;
+    assert( pBuf->nBuf<=pBuf->nAlloc );
   }
-  return SQLITE_OK;
 }
 
-/* Append the name of the path for element i to pStr
+/*
+** This function is called when rebasing a local UPDATE change against one 
+** or more remote UPDATE changes. The aRec/nRec buffer contains the current
+** old.* and new.* records for the change. The rebase buffer (a single
+** record) is in aChange/nChange. The rebased change is appended to buffer
+** pBuf.
+**
+** Rebasing the UPDATE involves: 
+**
+**   * Removing any changes to fields for which the corresponding field
+**     in the rebase buffer is set to "replaced" (type 0xFF). If this
+**     means the UPDATE change updates no fields, nothing is appended
+**     to the output buffer.
+**
+**   * For each field modified by the local change for which the 
+**     corresponding field in the rebase buffer is not "undefined" (0x00)
+**     or "replaced" (0xFF), the old.* value is replaced by the value
+**     in the rebase buffer.
 */
-static void jsonEachComputePath(
-  JsonEachCursor *p,       /* The cursor */
-  JsonString *pStr,        /* Write the path here */
-  u32 i                    /* Path to this element */
+static void sessionAppendPartialUpdate(
+  SessionBuffer *pBuf,            /* Append record here */
+  sqlite3_changeset_iter *pIter,  /* Iterator pointed at local change */
+  u8 *aRec, int nRec,             /* Local change */
+  u8 *aChange, int nChange,       /* Record to rebase against */
+  int *pRc                        /* IN/OUT: Return Code */
 ){
-  JsonNode *pNode, *pUp;
-  u32 iUp;
-  if( i==0 ){
-    jsonAppendChar(pStr, '$');
-    return;
-  }
-  iUp = p->sParse.aUp[i];
-  jsonEachComputePath(p, pStr, iUp);
-  pNode = &p->sParse.aNode[i];
-  pUp = &p->sParse.aNode[iUp];
-  if( pUp->eType==JSON_ARRAY ){
-    jsonPrintf(30, pStr, "[%d]", pUp->u.iKey);
-  }else{
-    assert( pUp->eType==JSON_OBJECT );
-    if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--;
-    assert( pNode->eType==JSON_STRING );
-    assert( pNode->jnFlags & JNODE_LABEL );
-    jsonPrintf(pNode->n+1, pStr, ".%.*s", pNode->n-2, pNode->u.zJContent+1);
-  }
-}
+  sessionBufferGrow(pBuf, 2+nRec+nChange, pRc);
+  if( *pRc==SQLITE_OK ){
+    int bData = 0;
+    u8 *pOut = &pBuf->aBuf[pBuf->nBuf];
+    int i;
+    u8 *a1 = aRec;
+    u8 *a2 = aChange;
 
-/* Return the value of a column */
-static int jsonEachColumn(
-  sqlite3_vtab_cursor *cur,   /* The cursor */
-  sqlite3_context *ctx,       /* First argument to sqlite3_result_...() */
-  int i                       /* Which column to return */
-){
-  JsonEachCursor *p = (JsonEachCursor*)cur;
-  JsonNode *pThis = &p->sParse.aNode[p->i];
-  switch( i ){
-    case JEACH_KEY: {
-      if( p->i==0 ) break;
-      if( p->eType==JSON_OBJECT ){
-        jsonReturn(pThis, ctx, 0);
-      }else if( p->eType==JSON_ARRAY ){
-        u32 iKey;
-        if( p->bRecursive ){
-          if( p->iRowid==0 ) break;
-          iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey;
+    *pOut++ = SQLITE_UPDATE;
+    *pOut++ = pIter->bIndirect;
+    for(i=0; i<pIter->nCol; i++){
+      int n1 = sessionSerialLen(a1);
+      int n2 = sessionSerialLen(a2);
+      if( pIter->abPK[i] || a2[0]==0 ){
+        if( !pIter->abPK[i] ) bData = 1;
+        memcpy(pOut, a1, n1);
+        pOut += n1;
+      }else if( a2[0]!=0xFF ){
+        bData = 1;
+        memcpy(pOut, a2, n2);
+        pOut += n2;
+      }else{
+        *pOut++ = '\0';
+      }
+      a1 += n1;
+      a2 += n2;
+    }
+    if( bData ){
+      a2 = aChange;
+      for(i=0; i<pIter->nCol; i++){
+        int n1 = sessionSerialLen(a1);
+        int n2 = sessionSerialLen(a2);
+        if( pIter->abPK[i] || a2[0]!=0xFF ){
+          memcpy(pOut, a1, n1);
+          pOut += n1;
         }else{
-          iKey = p->iRowid;
+          *pOut++ = '\0';
         }
-        sqlite3_result_int64(ctx, (sqlite3_int64)iKey);
+        a1 += n1;
+        a2 += n2;
       }
-      break;
-    }
-    case JEACH_VALUE: {
-      if( pThis->jnFlags & JNODE_LABEL ) pThis++;
-      jsonReturn(pThis, ctx, 0);
-      break;
-    }
-    case JEACH_TYPE: {
-      if( pThis->jnFlags & JNODE_LABEL ) pThis++;
-      sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC);
-      break;
-    }
-    case JEACH_ATOM: {
-      if( pThis->jnFlags & JNODE_LABEL ) pThis++;
-      if( pThis->eType>=JSON_ARRAY ) break;
-      jsonReturn(pThis, ctx, 0);
-      break;
-    }
-    case JEACH_ID: {
-      sqlite3_result_int64(ctx, 
-         (sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0));
-      break;
+      pBuf->nBuf = (pOut - pBuf->aBuf);
     }
-    case JEACH_PARENT: {
-      if( p->i>p->iBegin && p->bRecursive ){
-        sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]);
+  }
+}
+
+/*
+** pIter is configured to iterate through a changeset. This function rebases 
+** that changeset according to the current configuration of the rebaser 
+** object passed as the first argument. If no error occurs and argument xOutput
+** is not NULL, then the changeset is returned to the caller by invoking
+** xOutput zero or more times and SQLITE_OK returned. Or, if xOutput is NULL,
+** then (*ppOut) is set to point to a buffer containing the rebased changeset
+** before this function returns. In this case (*pnOut) is set to the size of
+** the buffer in bytes.  It is the responsibility of the caller to eventually
+** free the (*ppOut) buffer using sqlite3_free(). 
+**
+** If an error occurs, an SQLite error code is returned. If ppOut and
+** pnOut are not NULL, then the two output parameters are set to 0 before
+** returning.
+*/
+static int sessionRebase(
+  sqlite3_rebaser *p,             /* Rebaser hash table */
+  sqlite3_changeset_iter *pIter,  /* Input data */
+  int (*xOutput)(void *pOut, const void *pData, int nData),
+  void *pOut,                     /* Context for xOutput callback */
+  int *pnOut,                     /* OUT: Number of bytes in output changeset */
+  void **ppOut                    /* OUT: Inverse of pChangeset */
+){
+  int rc = SQLITE_OK;
+  u8 *aRec = 0;
+  int nRec = 0;
+  int bNew = 0;
+  SessionTable *pTab = 0;
+  SessionBuffer sOut = {0,0,0};
+
+  while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec, &bNew) ){
+    SessionChange *pChange = 0;
+    int bDone = 0;
+
+    if( bNew ){
+      const char *zTab = pIter->zTab;
+      for(pTab=p->grp.pList; pTab; pTab=pTab->pNext){
+        if( 0==sqlite3_stricmp(pTab->zName, zTab) ) break;
       }
-      break;
+      bNew = 0;
+
+      /* A patchset may not be rebased */
+      if( pIter->bPatchset ){
+        rc = SQLITE_ERROR;
+      }
+
+      /* Append a table header to the output for this new table */
+      sessionAppendByte(&sOut, pIter->bPatchset ? 'P' : 'T', &rc);
+      sessionAppendVarint(&sOut, pIter->nCol, &rc);
+      sessionAppendBlob(&sOut, pIter->abPK, pIter->nCol, &rc);
+      sessionAppendBlob(&sOut,(u8*)pIter->zTab,(int)strlen(pIter->zTab)+1,&rc);
     }
-    case JEACH_FULLKEY: {
-      JsonString x;
-      jsonInit(&x, ctx);
-      if( p->bRecursive ){
-        jsonEachComputePath(p, &x, p->i);
-      }else{
-        if( p->zRoot ){
-          jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot));
-        }else{
-          jsonAppendChar(&x, '$');
-        }
-        if( p->eType==JSON_ARRAY ){
-          jsonPrintf(30, &x, "[%d]", p->iRowid);
-        }else if( p->eType==JSON_OBJECT ){
-          jsonPrintf(pThis->n, &x, ".%.*s", pThis->n-2, pThis->u.zJContent+1);
+
+    if( pTab && rc==SQLITE_OK ){
+      int iHash = sessionChangeHash(pTab, 0, aRec, pTab->nChange);
+
+      for(pChange=pTab->apChange[iHash]; pChange; pChange=pChange->pNext){
+        if( sessionChangeEqual(pTab, 0, aRec, 0, pChange->aRecord) ){
+          break;
         }
       }
-      jsonResult(&x);
-      break;
     }
-    case JEACH_PATH: {
-      if( p->bRecursive ){
-        JsonString x;
-        jsonInit(&x, ctx);
-        jsonEachComputePath(p, &x, p->sParse.aUp[p->i]);
-        jsonResult(&x);
-        break;
+
+    if( pChange ){
+      assert( pChange->op==SQLITE_DELETE || pChange->op==SQLITE_INSERT );
+      switch( pIter->op ){
+        case SQLITE_INSERT:
+          if( pChange->op==SQLITE_INSERT ){
+            bDone = 1;
+            if( pChange->bIndirect==0 ){
+              sessionAppendByte(&sOut, SQLITE_UPDATE, &rc);
+              sessionAppendByte(&sOut, pIter->bIndirect, &rc);
+              sessionAppendBlob(&sOut, pChange->aRecord, pChange->nRecord, &rc);
+              sessionAppendBlob(&sOut, aRec, nRec, &rc);
+            }
+          }
+          break;
+
+        case SQLITE_UPDATE:
+          bDone = 1;
+          if( pChange->op==SQLITE_DELETE ){
+            if( pChange->bIndirect==0 ){
+              u8 *pCsr = aRec;
+              sessionSkipRecord(&pCsr, pIter->nCol);
+              sessionAppendByte(&sOut, SQLITE_INSERT, &rc);
+              sessionAppendByte(&sOut, pIter->bIndirect, &rc);
+              sessionAppendRecordMerge(&sOut, pIter->nCol,
+                  pCsr, nRec-(pCsr-aRec), 
+                  pChange->aRecord, pChange->nRecord, &rc
+              );
+            }
+          }else{
+            sessionAppendPartialUpdate(&sOut, pIter,
+                aRec, nRec, pChange->aRecord, pChange->nRecord, &rc
+            );
+          }
+          break;
+
+        default:
+          assert( pIter->op==SQLITE_DELETE );
+          bDone = 1;
+          if( pChange->op==SQLITE_INSERT ){
+            sessionAppendByte(&sOut, SQLITE_DELETE, &rc);
+            sessionAppendByte(&sOut, pIter->bIndirect, &rc);
+            sessionAppendRecordMerge(&sOut, pIter->nCol,
+                pChange->aRecord, pChange->nRecord, aRec, nRec, &rc
+            );
+          }
+          break;
       }
-      /* For json_each() path and root are the same so fall through
-      ** into the root case */
     }
-    default: {
-      const char *zRoot = p->zRoot;
-      if( zRoot==0 ) zRoot = "$";
-      sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
-      break;
+
+    if( bDone==0 ){
+      sessionAppendByte(&sOut, pIter->op, &rc);
+      sessionAppendByte(&sOut, pIter->bIndirect, &rc);
+      sessionAppendBlob(&sOut, aRec, nRec, &rc);
     }
-    case JEACH_JSON: {
-      assert( i==JEACH_JSON );
-      sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC);
-      break;
+    if( rc==SQLITE_OK && xOutput && sOut.nBuf>SESSIONS_STRM_CHUNK_SIZE ){
+      rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
+      sOut.nBuf = 0;
     }
+    if( rc ) break;
   }
-  return SQLITE_OK;
-}
 
-/* Return the current rowid value */
-static int jsonEachRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
-  JsonEachCursor *p = (JsonEachCursor*)cur;
-  *pRowid = p->iRowid;
-  return SQLITE_OK;
+  if( rc!=SQLITE_OK ){
+    sqlite3_free(sOut.aBuf);
+    memset(&sOut, 0, sizeof(sOut));
+  }
+
+  if( rc==SQLITE_OK ){
+    if( xOutput ){
+      if( sOut.nBuf>0 ){
+        rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
+      }
+    }else{
+      *ppOut = (void*)sOut.aBuf;
+      *pnOut = sOut.nBuf;
+      sOut.aBuf = 0;
+    }
+  }
+  sqlite3_free(sOut.aBuf);
+  return rc;
 }
 
-/* The query strategy is to look for an equality constraint on the json
-** column.  Without such a constraint, the table cannot operate.  idxNum is
-** 1 if the constraint is found, 3 if the constraint and zRoot are found,
-** and 0 otherwise.
+/* 
+** Create a new rebaser object.
 */
-static int jsonEachBestIndex(
-  sqlite3_vtab *tab,
-  sqlite3_index_info *pIdxInfo
-){
-  int i;
-  int jsonIdx = -1;
-  int rootIdx = -1;
-  const struct sqlite3_index_constraint *pConstraint;
+SQLITE_API int sqlite3rebaser_create(sqlite3_rebaser **ppNew){
+  int rc = SQLITE_OK;
+  sqlite3_rebaser *pNew;
 
-  UNUSED_PARAM(tab);
-  pConstraint = pIdxInfo->aConstraint;
-  for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
-    if( pConstraint->usable==0 ) continue;
-    if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
-    switch( pConstraint->iColumn ){
-      case JEACH_JSON:   jsonIdx = i;    break;
-      case JEACH_ROOT:   rootIdx = i;    break;
-      default:           /* no-op */     break;
-    }
-  }
-  if( jsonIdx<0 ){
-    pIdxInfo->idxNum = 0;
-    pIdxInfo->estimatedCost = 1e99;
+  pNew = sqlite3_malloc(sizeof(sqlite3_rebaser));
+  if( pNew==0 ){
+    rc = SQLITE_NOMEM;
   }else{
-    pIdxInfo->estimatedCost = 1.0;
-    pIdxInfo->aConstraintUsage[jsonIdx].argvIndex = 1;
-    pIdxInfo->aConstraintUsage[jsonIdx].omit = 1;
-    if( rootIdx<0 ){
-      pIdxInfo->idxNum = 1;
-    }else{
-      pIdxInfo->aConstraintUsage[rootIdx].argvIndex = 2;
-      pIdxInfo->aConstraintUsage[rootIdx].omit = 1;
-      pIdxInfo->idxNum = 3;
-    }
+    memset(pNew, 0, sizeof(sqlite3_rebaser));
   }
-  return SQLITE_OK;
+  *ppNew = pNew;
+  return rc;
 }
 
-/* Start a search on a new JSON string */
-static int jsonEachFilter(
-  sqlite3_vtab_cursor *cur,
-  int idxNum, const char *idxStr,
-  int argc, sqlite3_value **argv
+/* 
+** Call this one or more times to configure a rebaser.
+*/
+SQLITE_API int sqlite3rebaser_configure(
+  sqlite3_rebaser *p, 
+  int nRebase, const void *pRebase
 ){
-  JsonEachCursor *p = (JsonEachCursor*)cur;
-  const char *z;
-  const char *zRoot = 0;
-  sqlite3_int64 n;
-
-  UNUSED_PARAM(idxStr);
-  UNUSED_PARAM(argc);
-  jsonEachCursorReset(p);
-  if( idxNum==0 ) return SQLITE_OK;
-  z = (const char*)sqlite3_value_text(argv[0]);
-  if( z==0 ) return SQLITE_OK;
-  n = sqlite3_value_bytes(argv[0]);
-  p->zJson = sqlite3_malloc64( n+1 );
-  if( p->zJson==0 ) return SQLITE_NOMEM;
-  memcpy(p->zJson, z, (size_t)n+1);
-  if( jsonParse(&p->sParse, 0, p->zJson) ){
-    int rc = SQLITE_NOMEM;
-    if( p->sParse.oom==0 ){
-      sqlite3_free(cur->pVtab->zErrMsg);
-      cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON");
-      if( cur->pVtab->zErrMsg ) rc = SQLITE_ERROR;
-    }
-    jsonEachCursorReset(p);
-    return rc;
-  }else if( p->bRecursive && jsonParseFindParents(&p->sParse) ){
-    jsonEachCursorReset(p);
-    return SQLITE_NOMEM;
-  }else{
-    JsonNode *pNode = 0;
-    if( idxNum==3 ){
-      const char *zErr = 0;
-      zRoot = (const char*)sqlite3_value_text(argv[1]);
-      if( zRoot==0 ) return SQLITE_OK;
-      n = sqlite3_value_bytes(argv[1]);
-      p->zRoot = sqlite3_malloc64( n+1 );
-      if( p->zRoot==0 ) return SQLITE_NOMEM;
-      memcpy(p->zRoot, zRoot, (size_t)n+1);
-      if( zRoot[0]!='$' ){
-        zErr = zRoot;
-      }else{
-        pNode = jsonLookupStep(&p->sParse, 0, p->zRoot+1, 0, &zErr);
-      }
-      if( zErr ){
-        sqlite3_free(cur->pVtab->zErrMsg);
-        cur->pVtab->zErrMsg = jsonPathSyntaxError(zErr);
-        jsonEachCursorReset(p);
-        return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
-      }else if( pNode==0 ){
-        return SQLITE_OK;
-      }
-    }else{
-      pNode = p->sParse.aNode;
-    }
-    p->iBegin = p->i = (int)(pNode - p->sParse.aNode);
-    p->eType = pNode->eType;
-    if( p->eType>=JSON_ARRAY ){
-      pNode->u.iKey = 0;
-      p->iEnd = p->i + pNode->n + 1;
-      if( p->bRecursive ){
-        p->eType = p->sParse.aNode[p->sParse.aUp[p->i]].eType;
-        if( p->i>0 && (p->sParse.aNode[p->i-1].jnFlags & JNODE_LABEL)!=0 ){
-          p->i--;
-        }
-      }else{
-        p->i++;
-      }
-    }else{
-      p->iEnd = p->i+1;
-    }
+  sqlite3_changeset_iter *pIter = 0;   /* Iterator opened on pData/nData */
+  int rc;                              /* Return code */
+  rc = sqlite3changeset_start(&pIter, nRebase, (void*)pRebase);
+  if( rc==SQLITE_OK ){
+    rc = sessionChangesetToHash(pIter, &p->grp, 1);
   }
-  return SQLITE_OK;
+  sqlite3changeset_finalize(pIter);
+  return rc;
 }
 
-/* The methods of the json_each virtual table */
-static sqlite3_module jsonEachModule = {
-  0,                         /* iVersion */
-  0,                         /* xCreate */
-  jsonEachConnect,           /* xConnect */
-  jsonEachBestIndex,         /* xBestIndex */
-  jsonEachDisconnect,        /* xDisconnect */
-  0,                         /* xDestroy */
-  jsonEachOpenEach,          /* xOpen - open a cursor */
-  jsonEachClose,             /* xClose - close a cursor */
-  jsonEachFilter,            /* xFilter - configure scan constraints */
-  jsonEachNext,              /* xNext - advance a cursor */
-  jsonEachEof,               /* xEof - check for end of scan */
-  jsonEachColumn,            /* xColumn - read data */
-  jsonEachRowid,             /* xRowid - read data */
-  0,                         /* xUpdate */
-  0,                         /* xBegin */
-  0,                         /* xSync */
-  0,                         /* xCommit */
-  0,                         /* xRollback */
-  0,                         /* xFindMethod */
-  0,                         /* xRename */
-  0,                         /* xSavepoint */
-  0,                         /* xRelease */
-  0                          /* xRollbackTo */
-};
+/* 
+** Rebase a changeset according to current rebaser configuration 
+*/
+SQLITE_API int sqlite3rebaser_rebase(
+  sqlite3_rebaser *p,
+  int nIn, const void *pIn, 
+  int *pnOut, void **ppOut 
+){
+  sqlite3_changeset_iter *pIter = 0;   /* Iterator to skip through input */  
+  int rc = sqlite3changeset_start(&pIter, nIn, (void*)pIn);
 
-/* The methods of the json_tree virtual table. */
-static sqlite3_module jsonTreeModule = {
-  0,                         /* iVersion */
-  0,                         /* xCreate */
-  jsonEachConnect,           /* xConnect */
-  jsonEachBestIndex,         /* xBestIndex */
-  jsonEachDisconnect,        /* xDisconnect */
-  0,                         /* xDestroy */
-  jsonEachOpenTree,          /* xOpen - open a cursor */
-  jsonEachClose,             /* xClose - close a cursor */
-  jsonEachFilter,            /* xFilter - configure scan constraints */
-  jsonEachNext,              /* xNext - advance a cursor */
-  jsonEachEof,               /* xEof - check for end of scan */
-  jsonEachColumn,            /* xColumn - read data */
-  jsonEachRowid,             /* xRowid - read data */
-  0,                         /* xUpdate */
-  0,                         /* xBegin */
-  0,                         /* xSync */
-  0,                         /* xCommit */
-  0,                         /* xRollback */
-  0,                         /* xFindMethod */
-  0,                         /* xRename */
-  0,                         /* xSavepoint */
-  0,                         /* xRelease */
-  0                          /* xRollbackTo */
-};
-#endif /* SQLITE_OMIT_VIRTUALTABLE */
+  if( rc==SQLITE_OK ){
+    rc = sessionRebase(p, pIter, 0, 0, pnOut, ppOut);
+    sqlite3changeset_finalize(pIter);
+  }
 
-/****************************************************************************
-** The following routines are the only publically visible identifiers in this
-** file.  Call the following routines in order to register the various SQL
-** functions and the virtual table implemented by this file.
-****************************************************************************/
+  return rc;
+}
 
-SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){
-  int rc = SQLITE_OK;
-  unsigned int i;
-  static const struct {
-     const char *zName;
-     int nArg;
-     int flag;
-     void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
-  } aFunc[] = {
-    { "json",                 1, 0,   jsonRemoveFunc        },
-    { "json_array",          -1, 0,   jsonArrayFunc         },
-    { "json_array_length",    1, 0,   jsonArrayLengthFunc   },
-    { "json_array_length",    2, 0,   jsonArrayLengthFunc   },
-    { "json_extract",        -1, 0,   jsonExtractFunc       },
-    { "json_insert",         -1, 0,   jsonSetFunc           },
-    { "json_object",         -1, 0,   jsonObjectFunc        },
-    { "json_patch",           2, 0,   jsonPatchFunc         },
-    { "json_quote",           1, 0,   jsonQuoteFunc         },
-    { "json_remove",         -1, 0,   jsonRemoveFunc        },
-    { "json_replace",        -1, 0,   jsonReplaceFunc       },
-    { "json_set",            -1, 1,   jsonSetFunc           },
-    { "json_type",            1, 0,   jsonTypeFunc          },
-    { "json_type",            2, 0,   jsonTypeFunc          },
-    { "json_valid",           1, 0,   jsonValidFunc         },
+/* 
+** Rebase a changeset according to current rebaser configuration 
+*/
+SQLITE_API int sqlite3rebaser_rebase_strm(
+  sqlite3_rebaser *p,
+  int (*xInput)(void *pIn, void *pData, int *pnData),
+  void *pIn,
+  int (*xOutput)(void *pOut, const void *pData, int nData),
+  void *pOut
+){
+  sqlite3_changeset_iter *pIter = 0;   /* Iterator to skip through input */  
+  int rc = sqlite3changeset_start_strm(&pIter, xInput, pIn);
 
-#if SQLITE_DEBUG
-    /* DEBUG and TESTING functions */
-    { "json_parse",           1, 0,   jsonParseFunc         },
-    { "json_test1",           1, 0,   jsonTest1Func         },
-#endif
-  };
-  static const struct {
-     const char *zName;
-     int nArg;
-     void (*xStep)(sqlite3_context*,int,sqlite3_value**);
-     void (*xFinal)(sqlite3_context*);
-  } aAgg[] = {
-    { "json_group_array",     1,   jsonArrayStep,   jsonArrayFinal  },
-    { "json_group_object",    2,   jsonObjectStep,  jsonObjectFinal },
-  };
-#ifndef SQLITE_OMIT_VIRTUALTABLE
-  static const struct {
-     const char *zName;
-     sqlite3_module *pModule;
-  } aMod[] = {
-    { "json_each",            &jsonEachModule               },
-    { "json_tree",            &jsonTreeModule               },
-  };
-#endif
-  for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
-    rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg,
-                                 SQLITE_UTF8 | SQLITE_DETERMINISTIC, 
-                                 (void*)&aFunc[i].flag,
-                                 aFunc[i].xFunc, 0, 0);
-  }
-  for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
-    rc = sqlite3_create_function(db, aAgg[i].zName, aAgg[i].nArg,
-                                 SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
-                                 0, aAgg[i].xStep, aAgg[i].xFinal);
-  }
-#ifndef SQLITE_OMIT_VIRTUALTABLE
-  for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){
-    rc = sqlite3_create_module(db, aMod[i].zName, aMod[i].pModule, 0);
+  if( rc==SQLITE_OK ){
+    rc = sessionRebase(p, pIter, xOutput, pOut, 0, 0);
+    sqlite3changeset_finalize(pIter);
   }
-#endif
+
   return rc;
 }
 
-
-#ifndef SQLITE_CORE
-#ifdef _WIN32
-__declspec(dllexport)
-#endif
-SQLITE_API int sqlite3_json_init(
-  sqlite3 *db, 
-  char **pzErrMsg, 
-  const sqlite3_api_routines *pApi
-){
-  SQLITE_EXTENSION_INIT2(pApi);
-  (void)pzErrMsg;  /* Unused parameter */
-  return sqlite3Json1Init(db);
+/* 
+** Destroy a rebaser object 
+*/
+SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p){
+  if( p ){
+    sessionDeleteTable(p->grp.pList);
+    sqlite3_free(p);
+  }
 }
-#endif
-#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1) */
 
-/************** End of json1.c ***********************************************/
+#endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */
+
+/************** End of sqlite3session.c **************************************/
 /************** Begin file fts5.c ********************************************/
 
 
@@ -190621,7 +197422,7 @@ struct Fts5ExtensionApi {
 **            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
+**            'first + place' or '1st + place', as there are entries in the
 **            FTS index corresponding to both forms of the first token.
 **   </ol>
 **
@@ -190649,7 +197450,7 @@ struct Fts5ExtensionApi {
 **   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:
+**   token "first" is substituted for "1st" by the tokenizer, then the query:
 **
 **   <codeblock>
 **     ... MATCH '1s*'</codeblock>
@@ -191541,9 +198342,12 @@ static int sqlite3Fts5VocabInit(Fts5Global*, sqlite3*);
 /**************************************************************************
 ** Interface to automatically generated code in fts5_unicode2.c. 
 */
-static int sqlite3Fts5UnicodeIsalnum(int c);
 static int sqlite3Fts5UnicodeIsdiacritic(int c);
 static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
+
+static int sqlite3Fts5UnicodeCatParse(const char*, u8*);
+static int sqlite3Fts5UnicodeCategory(int iCode);
+static void sqlite3Fts5UnicodeAscii(u8*, u8*);
 /*
 ** End of interface to code in fts5_unicode2.c.
 **************************************************************************/
@@ -191719,6 +198523,7 @@ typedef union {
 #define fts5YY_MIN_REDUCE        83
 #define fts5YY_MAX_REDUCE        110
 /************* End control #defines *******************************************/
+#define fts5YY_NLOOKAHEAD ((int)(sizeof(fts5yy_lookahead)/sizeof(fts5yy_lookahead[0])))
 
 /* Define the fts5yytestcase() macro to be a no-op if is not already defined
 ** otherwise.
@@ -192278,11 +199083,11 @@ static fts5YYACTIONTYPE fts5yy_find_shift_action(
   do{
     i = fts5yy_shift_ofst[stateno];
     assert( i>=0 );
-    assert( i+fts5YYNFTS5TOKEN<=(int)sizeof(fts5yy_lookahead)/sizeof(fts5yy_lookahead[0]) );
+    /* assert( i+fts5YYNFTS5TOKEN<=(int)fts5YY_NLOOKAHEAD ); */
     assert( iLookAhead!=fts5YYNOCODE );
     assert( iLookAhead < fts5YYNFTS5TOKEN );
     i += iLookAhead;
-    if( fts5yy_lookahead[i]!=iLookAhead ){
+    if( i>=fts5YY_NLOOKAHEAD || fts5yy_lookahead[i]!=iLookAhead ){
 #ifdef fts5YYFALLBACK
       fts5YYCODETYPE iFallback;            /* Fallback token */
       if( iLookAhead<sizeof(fts5yyFallback)/sizeof(fts5yyFallback[0])
@@ -192308,6 +199113,7 @@ static fts5YYACTIONTYPE fts5yy_find_shift_action(
 #if fts5YY_SHIFT_MAX+fts5YYWILDCARD>=fts5YY_ACTTAB_COUNT
           j<fts5YY_ACTTAB_COUNT &&
 #endif
+          j<(int)(sizeof(fts5yy_lookahead)/sizeof(fts5yy_lookahead[0])) &&
           fts5yy_lookahead[j]==fts5YYWILDCARD && iLookAhead>0
         ){
 #ifndef NDEBUG
@@ -192332,7 +199138,7 @@ static fts5YYACTIONTYPE fts5yy_find_shift_action(
 ** Find the appropriate action for a parser given the non-terminal
 ** look-ahead token iLookAhead.
 */
-static int fts5yy_find_reduce_action(
+static fts5YYACTIONTYPE fts5yy_find_reduce_action(
   fts5YYACTIONTYPE stateno,     /* Current state number */
   fts5YYCODETYPE iLookAhead     /* The look-ahead token */
 ){
@@ -192500,7 +199306,7 @@ static fts5YYACTIONTYPE fts5yy_reduce(
   sqlite3Fts5ParserCTX_PDECL                   /* %extra_context */
 ){
   int fts5yygoto;                     /* The next state */
-  int fts5yyact;                      /* The next action */
+  fts5YYACTIONTYPE fts5yyact;             /* The next action */
   fts5yyStackEntry *fts5yymsp;            /* The top of the parser's stack */
   int fts5yysize;                     /* Amount to pop the stack */
   sqlite3Fts5ParserARG_FETCH
@@ -192856,12 +199662,12 @@ static void sqlite3Fts5Parser(
 
   do{
     assert( fts5yyact==fts5yypParser->fts5yytos->stateno );
-    fts5yyact = fts5yy_find_shift_action(fts5yymajor,fts5yyact);
+    fts5yyact = fts5yy_find_shift_action((fts5YYCODETYPE)fts5yymajor,fts5yyact);
     if( fts5yyact >= fts5YY_MIN_REDUCE ){
       fts5yyact = fts5yy_reduce(fts5yypParser,fts5yyact-fts5YY_MIN_REDUCE,fts5yymajor,
                         fts5yyminor sqlite3Fts5ParserCTX_PARAM);
     }else if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){
-      fts5yy_shift(fts5yypParser,fts5yyact,fts5yymajor,fts5yyminor);
+      fts5yy_shift(fts5yypParser,fts5yyact,(fts5YYCODETYPE)fts5yymajor,fts5yyminor);
 #ifndef fts5YYNOERRORRECOVERY
       fts5yypParser->fts5yyerrcnt--;
 #endif
@@ -192989,6 +199795,21 @@ static void sqlite3Fts5Parser(
   return;
 }
 
+/*
+** Return the fallback token corresponding to canonical token iToken, or
+** 0 if iToken has no fallback.
+*/
+static int sqlite3Fts5ParserFallback(int iToken){
+#ifdef fts5YYFALLBACK
+  if( iToken<(int)(sizeof(fts5yyFallback)/sizeof(fts5yyFallback[0])) ){
+    return fts5yyFallback[iToken];
+  }
+#else
+  (void)iToken;
+#endif
+  return 0;
+}
+
 /*
 ** 2014 May 31
 **
@@ -195099,6 +201920,7 @@ static void sqlite3Fts5Parser(void*, int, Fts5Token, Fts5Parse*);
 /* #include <stdio.h> */
 static void sqlite3Fts5ParserTrace(FILE*, char*);
 #endif
+static int sqlite3Fts5ParserFallback(int);
 
 
 struct Fts5Expr {
@@ -197603,14 +204425,19 @@ static void fts5ExprIsAlnum(
   sqlite3_value **apVal           /* Function arguments */
 ){
   int iCode;
+  u8 aArr[32];
   if( nArg!=1 ){
     sqlite3_result_error(pCtx, 
         "wrong number of arguments to function fts5_isalnum", -1
     );
     return;
   }
+  memset(aArr, 0, sizeof(aArr));
+  sqlite3Fts5UnicodeCatParse("L*", aArr);
+  sqlite3Fts5UnicodeCatParse("N*", aArr);
+  sqlite3Fts5UnicodeCatParse("Co", aArr);
   iCode = sqlite3_value_int(apVal[0]);
-  sqlite3_result_int(pCtx, sqlite3Fts5UnicodeIsalnum(iCode));
+  sqlite3_result_int(pCtx, aArr[sqlite3Fts5UnicodeCategory(iCode)]);
 }
 
 static void fts5ExprFold(
@@ -197654,10 +204481,12 @@ static int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){
     rc = sqlite3_create_function(db, p->z, -1, SQLITE_UTF8, pCtx, p->x, 0, 0);
   }
 
-  /* Avoid a warning indicating that sqlite3Fts5ParserTrace() is unused */
+  /* Avoid warnings indicating that sqlite3Fts5ParserTrace() and
+  ** sqlite3Fts5ParserFallback() are unused */
 #ifndef NDEBUG
   (void)sqlite3Fts5ParserTrace;
 #endif
+  (void)sqlite3Fts5ParserFallback;
 
   return rc;
 }
@@ -203705,7 +210534,10 @@ static int sqlite3Fts5IndexCharlenToBytelen(
   for(i=0; i<nChar; i++){
     if( n>=nByte ) return 0;      /* Input contains fewer than nChar chars */
     if( (unsigned char)p[n++]>=0xc0 ){
-      while( (p[n] & 0xc0)==0x80 ) n++;
+      while( (p[n] & 0xc0)==0x80 ){
+        n++;
+        if( n>=nByte ) break;
+      }
     }
   }
   return n;
@@ -205230,7 +212062,7 @@ static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){
     case FTS5_SAVEPOINT:
       assert( p->ts.eState==1 );
       assert( iSavepoint>=0 );
-      assert( iSavepoint>p->ts.iSavepoint );
+      assert( iSavepoint>=p->ts.iSavepoint );
       p->ts.iSavepoint = iSavepoint;
       break;
       
@@ -206155,6 +212987,13 @@ static int fts5FilterMethod(
     assert( nVal==0 && pMatch==0 && bOrderByRank==0 && bDesc==0 );
     assert( pCsr->iLastRowid==LARGEST_INT64 );
     assert( pCsr->iFirstRowid==SMALLEST_INT64 );
+    if( pTab->pSortCsr->bDesc ){
+      pCsr->iLastRowid = pTab->pSortCsr->iFirstRowid;
+      pCsr->iFirstRowid = pTab->pSortCsr->iLastRowid;
+    }else{
+      pCsr->iLastRowid = pTab->pSortCsr->iLastRowid;
+      pCsr->iFirstRowid = pTab->pSortCsr->iFirstRowid;
+    }
     pCsr->ePlan = FTS5_PLAN_SOURCE;
     pCsr->pExpr = pTab->pSortCsr->pExpr;
     rc = fts5CursorFirst(pTab, pCsr, bDesc);
@@ -207585,7 +214424,7 @@ static void fts5SourceIdFunc(
 ){
   assert( nArg==0 );
   UNUSED_PARAM2(nArg, apUnused);
-  sqlite3_result_text(pCtx, "fts5: 2018-06-04 19:24:41 c7ee0833225bfd8c5ec2f9bf62b97c4e04d03bd9566366d5221ac8fb199a87ca", -1, SQLITE_TRANSIENT);
+  sqlite3_result_text(pCtx, "fts5: 2018-09-18 20:20:44 2ac9003de44da7dafa3fbb1915ac5725a9275c86bf2f3b7aa19321bf1460b386", -1, SQLITE_TRANSIENT);
 }
 
 static int fts5Init(sqlite3 *db){
@@ -209073,6 +215912,8 @@ struct Unicode61Tokenizer {
   int bRemoveDiacritic;           /* True if remove_diacritics=1 is set */
   int nException;
   int *aiException;
+
+  unsigned char aCategory[32];    /* True for token char categories */
 };
 
 static int fts5UnicodeAddExceptions(
@@ -209097,7 +215938,7 @@ static int fts5UnicodeAddExceptions(
         if( iCode<128 ){
           p->aTokenChar[iCode] = (unsigned char)bTokenChars;
         }else{
-          bToken = sqlite3Fts5UnicodeIsalnum(iCode);
+          bToken = p->aCategory[sqlite3Fts5UnicodeCategory(iCode)];
           assert( (bToken==0 || bToken==1) ); 
           assert( (bTokenChars==0 || bTokenChars==1) );
           if( bToken!=bTokenChars && sqlite3Fts5UnicodeIsdiacritic(iCode)==0 ){
@@ -209158,6 +215999,21 @@ static void fts5UnicodeDelete(Fts5Tokenizer *pTok){
   return;
 }
 
+static int unicodeSetCategories(Unicode61Tokenizer *p, const char *zCat){
+  const char *z = zCat;
+
+  while( *z ){
+    while( *z==' ' || *z=='\t' ) z++;
+    if( *z && sqlite3Fts5UnicodeCatParse(z, p->aCategory) ){
+      return SQLITE_ERROR;
+    }
+    while( *z!=' ' && *z!='\t' && *z!='\0' ) z++;
+  }
+
+  sqlite3Fts5UnicodeAscii(p->aCategory, p->aTokenChar);
+  return SQLITE_OK;
+}
+
 /*
 ** Create a "unicode61" tokenizer.
 */
@@ -209176,15 +216032,28 @@ static int fts5UnicodeCreate(
   }else{
     p = (Unicode61Tokenizer*)sqlite3_malloc(sizeof(Unicode61Tokenizer));
     if( p ){
+      const char *zCat = "L* N* Co";
       int i;
       memset(p, 0, sizeof(Unicode61Tokenizer));
-      memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar));
+
       p->bRemoveDiacritic = 1;
       p->nFold = 64;
       p->aFold = sqlite3_malloc(p->nFold * sizeof(char));
       if( p->aFold==0 ){
         rc = SQLITE_NOMEM;
       }
+
+      /* Search for a "categories" argument */
+      for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
+        if( 0==sqlite3_stricmp(azArg[i], "categories") ){
+          zCat = azArg[i+1];
+        }
+      }
+
+      if( rc==SQLITE_OK ){
+        rc = unicodeSetCategories(p, zCat);
+      }
+
       for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
         const char *zArg = azArg[i+1];
         if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
@@ -209198,10 +216067,14 @@ static int fts5UnicodeCreate(
         }else
         if( 0==sqlite3_stricmp(azArg[i], "separators") ){
           rc = fts5UnicodeAddExceptions(p, zArg, 0);
+        }else
+        if( 0==sqlite3_stricmp(azArg[i], "categories") ){
+          /* no-op */
         }else{
           rc = SQLITE_ERROR;
         }
       }
+
     }else{
       rc = SQLITE_NOMEM;
     }
@@ -209220,8 +216093,10 @@ static int fts5UnicodeCreate(
 ** character (not a separator).
 */
 static int fts5UnicodeIsAlnum(Unicode61Tokenizer *p, int iCode){
-  assert( (sqlite3Fts5UnicodeIsalnum(iCode) & 0xFFFFFFFE)==0 );
-  return sqlite3Fts5UnicodeIsalnum(iCode) ^ fts5UnicodeIsException(p, iCode);
+  return (
+    p->aCategory[sqlite3Fts5UnicodeCategory(iCode)]
+    ^ fts5UnicodeIsException(p, iCode)
+  );
 }
 
 static int fts5UnicodeTokenize(
@@ -210097,135 +216972,6 @@ static int sqlite3Fts5TokenizerInit(fts5_api *pApi){
 
 /* #include <assert.h> */
 
-/*
-** 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.
-*/
-static int sqlite3Fts5UnicodeIsalnum(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] & (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]<key );
-    assert( key>=aEntry[iRes] );
-    return (((unsigned int)c) >= ((aEntry[iRes]>>10) + (aEntry[iRes]&0x3FF)));
-  }
-  return 1;
-}
 
 
 /*
@@ -210438,6 +217184,539 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){
   return ret;
 }
 
+
+#if 0
+static int sqlite3Fts5UnicodeNCat(void) { 
+  return 32;
+}
+#endif
+
+static int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){ 
+  aArray[0] = 1;
+  switch( zCat[0] ){
+    case 'C':
+          switch( zCat[1] ){
+            case 'c': aArray[1] = 1; break;
+            case 'f': aArray[2] = 1; break;
+            case 'n': aArray[3] = 1; break;
+            case 's': aArray[4] = 1; break;
+            case 'o': aArray[31] = 1; break;
+            case '*': 
+              aArray[1] = 1;
+              aArray[2] = 1;
+              aArray[3] = 1;
+              aArray[4] = 1;
+              aArray[31] = 1;
+              break;
+            default: return 1;          }
+          break;
+
+    case 'L':
+          switch( zCat[1] ){
+            case 'l': aArray[5] = 1; break;
+            case 'm': aArray[6] = 1; break;
+            case 'o': aArray[7] = 1; break;
+            case 't': aArray[8] = 1; break;
+            case 'u': aArray[9] = 1; break;
+            case 'C': aArray[30] = 1; break;
+            case '*': 
+              aArray[5] = 1;
+              aArray[6] = 1;
+              aArray[7] = 1;
+              aArray[8] = 1;
+              aArray[9] = 1;
+              aArray[30] = 1;
+              break;
+            default: return 1;          }
+          break;
+
+    case 'M':
+          switch( zCat[1] ){
+            case 'c': aArray[10] = 1; break;
+            case 'e': aArray[11] = 1; break;
+            case 'n': aArray[12] = 1; break;
+            case '*': 
+              aArray[10] = 1;
+              aArray[11] = 1;
+              aArray[12] = 1;
+              break;
+            default: return 1;          }
+          break;
+
+    case 'N':
+          switch( zCat[1] ){
+            case 'd': aArray[13] = 1; break;
+            case 'l': aArray[14] = 1; break;
+            case 'o': aArray[15] = 1; break;
+            case '*': 
+              aArray[13] = 1;
+              aArray[14] = 1;
+              aArray[15] = 1;
+              break;
+            default: return 1;          }
+          break;
+
+    case 'P':
+          switch( zCat[1] ){
+            case 'c': aArray[16] = 1; break;
+            case 'd': aArray[17] = 1; break;
+            case 'e': aArray[18] = 1; break;
+            case 'f': aArray[19] = 1; break;
+            case 'i': aArray[20] = 1; break;
+            case 'o': aArray[21] = 1; break;
+            case 's': aArray[22] = 1; break;
+            case '*': 
+              aArray[16] = 1;
+              aArray[17] = 1;
+              aArray[18] = 1;
+              aArray[19] = 1;
+              aArray[20] = 1;
+              aArray[21] = 1;
+              aArray[22] = 1;
+              break;
+            default: return 1;          }
+          break;
+
+    case 'S':
+          switch( zCat[1] ){
+            case 'c': aArray[23] = 1; break;
+            case 'k': aArray[24] = 1; break;
+            case 'm': aArray[25] = 1; break;
+            case 'o': aArray[26] = 1; break;
+            case '*': 
+              aArray[23] = 1;
+              aArray[24] = 1;
+              aArray[25] = 1;
+              aArray[26] = 1;
+              break;
+            default: return 1;          }
+          break;
+
+    case 'Z':
+          switch( zCat[1] ){
+            case 'l': aArray[27] = 1; break;
+            case 'p': aArray[28] = 1; break;
+            case 's': aArray[29] = 1; break;
+            case '*': 
+              aArray[27] = 1;
+              aArray[28] = 1;
+              aArray[29] = 1;
+              break;
+            default: return 1;          }
+          break;
+
+  }
+  return 0;
+}
+
+static u16 aFts5UnicodeBlock[] = {
+    0,     1471,  1753,  1760,  1760,  1760,  1760,  1760,  1760,  1760,  
+    1760,  1760,  1760,  1760,  1760,  1763,  1765,  
+  };
+static u16 aFts5UnicodeMap[] = {
+    0,     32,    33,    36,    37,    40,    41,    42,    43,    44,    
+    45,    46,    48,    58,    60,    63,    65,    91,    92,    93,    
+    94,    95,    96,    97,    123,   124,   125,   126,   127,   160,   
+    161,   162,   166,   167,   168,   169,   170,   171,   172,   173,   
+    174,   175,   176,   177,   178,   180,   181,   182,   184,   185,   
+    186,   187,   188,   191,   192,   215,   216,   223,   247,   248,   
+    256,   312,   313,   329,   330,   377,   383,   385,   387,   388,   
+    391,   394,   396,   398,   402,   403,   405,   406,   409,   412,   
+    414,   415,   417,   418,   423,   427,   428,   431,   434,   436,   
+    437,   440,   442,   443,   444,   446,   448,   452,   453,   454,   
+    455,   456,   457,   458,   459,   460,   461,   477,   478,   496,   
+    497,   498,   499,   500,   503,   505,   506,   564,   570,   572,   
+    573,   575,   577,   580,   583,   584,   592,   660,   661,   688,   
+    706,   710,   722,   736,   741,   748,   749,   750,   751,   768,   
+    880,   884,   885,   886,   890,   891,   894,   900,   902,   903,   
+    904,   908,   910,   912,   913,   931,   940,   975,   977,   978,   
+    981,   984,   1008,  1012,  1014,  1015,  1018,  1020,  1021,  1072,  
+    1120,  1154,  1155,  1160,  1162,  1217,  1231,  1232,  1329,  1369,  
+    1370,  1377,  1417,  1418,  1423,  1425,  1470,  1471,  1472,  1473,  
+    1475,  1476,  1478,  1479,  1488,  1520,  1523,  1536,  1542,  1545,  
+    1547,  1548,  1550,  1552,  1563,  1566,  1568,  1600,  1601,  1611,  
+    1632,  1642,  1646,  1648,  1649,  1748,  1749,  1750,  1757,  1758,  
+    1759,  1765,  1767,  1769,  1770,  1774,  1776,  1786,  1789,  1791,  
+    1792,  1807,  1808,  1809,  1810,  1840,  1869,  1958,  1969,  1984,  
+    1994,  2027,  2036,  2038,  2039,  2042,  2048,  2070,  2074,  2075,  
+    2084,  2085,  2088,  2089,  2096,  2112,  2137,  2142,  2208,  2210,  
+    2276,  2304,  2307,  2308,  2362,  2363,  2364,  2365,  2366,  2369,  
+    2377,  2381,  2382,  2384,  2385,  2392,  2402,  2404,  2406,  2416,  
+    2417,  2418,  2425,  2433,  2434,  2437,  2447,  2451,  2474,  2482,  
+    2486,  2492,  2493,  2494,  2497,  2503,  2507,  2509,  2510,  2519,  
+    2524,  2527,  2530,  2534,  2544,  2546,  2548,  2554,  2555,  2561,  
+    2563,  2565,  2575,  2579,  2602,  2610,  2613,  2616,  2620,  2622,  
+    2625,  2631,  2635,  2641,  2649,  2654,  2662,  2672,  2674,  2677,  
+    2689,  2691,  2693,  2703,  2707,  2730,  2738,  2741,  2748,  2749,  
+    2750,  2753,  2759,  2761,  2763,  2765,  2768,  2784,  2786,  2790,  
+    2800,  2801,  2817,  2818,  2821,  2831,  2835,  2858,  2866,  2869,  
+    2876,  2877,  2878,  2879,  2880,  2881,  2887,  2891,  2893,  2902,  
+    2903,  2908,  2911,  2914,  2918,  2928,  2929,  2930,  2946,  2947,  
+    2949,  2958,  2962,  2969,  2972,  2974,  2979,  2984,  2990,  3006,  
+    3008,  3009,  3014,  3018,  3021,  3024,  3031,  3046,  3056,  3059,  
+    3065,  3066,  3073,  3077,  3086,  3090,  3114,  3125,  3133,  3134,  
+    3137,  3142,  3146,  3157,  3160,  3168,  3170,  3174,  3192,  3199,  
+    3202,  3205,  3214,  3218,  3242,  3253,  3260,  3261,  3262,  3263,  
+    3264,  3270,  3271,  3274,  3276,  3285,  3294,  3296,  3298,  3302,  
+    3313,  3330,  3333,  3342,  3346,  3389,  3390,  3393,  3398,  3402,  
+    3405,  3406,  3415,  3424,  3426,  3430,  3440,  3449,  3450,  3458,  
+    3461,  3482,  3507,  3517,  3520,  3530,  3535,  3538,  3542,  3544,  
+    3570,  3572,  3585,  3633,  3634,  3636,  3647,  3648,  3654,  3655,  
+    3663,  3664,  3674,  3713,  3716,  3719,  3722,  3725,  3732,  3737,  
+    3745,  3749,  3751,  3754,  3757,  3761,  3762,  3764,  3771,  3773,  
+    3776,  3782,  3784,  3792,  3804,  3840,  3841,  3844,  3859,  3860,  
+    3861,  3864,  3866,  3872,  3882,  3892,  3893,  3894,  3895,  3896,  
+    3897,  3898,  3899,  3900,  3901,  3902,  3904,  3913,  3953,  3967,  
+    3968,  3973,  3974,  3976,  3981,  3993,  4030,  4038,  4039,  4046,  
+    4048,  4053,  4057,  4096,  4139,  4141,  4145,  4146,  4152,  4153,  
+    4155,  4157,  4159,  4160,  4170,  4176,  4182,  4184,  4186,  4190,  
+    4193,  4194,  4197,  4199,  4206,  4209,  4213,  4226,  4227,  4229,  
+    4231,  4237,  4238,  4239,  4240,  4250,  4253,  4254,  4256,  4295,  
+    4301,  4304,  4347,  4348,  4349,  4682,  4688,  4696,  4698,  4704,  
+    4746,  4752,  4786,  4792,  4800,  4802,  4808,  4824,  4882,  4888,  
+    4957,  4960,  4969,  4992,  5008,  5024,  5120,  5121,  5741,  5743,  
+    5760,  5761,  5787,  5788,  5792,  5867,  5870,  5888,  5902,  5906,  
+    5920,  5938,  5941,  5952,  5970,  5984,  5998,  6002,  6016,  6068,  
+    6070,  6071,  6078,  6086,  6087,  6089,  6100,  6103,  6104,  6107,  
+    6108,  6109,  6112,  6128,  6144,  6150,  6151,  6155,  6158,  6160,  
+    6176,  6211,  6212,  6272,  6313,  6314,  6320,  6400,  6432,  6435,  
+    6439,  6441,  6448,  6450,  6451,  6457,  6464,  6468,  6470,  6480,  
+    6512,  6528,  6576,  6593,  6600,  6608,  6618,  6622,  6656,  6679,  
+    6681,  6686,  6688,  6741,  6742,  6743,  6744,  6752,  6753,  6754,  
+    6755,  6757,  6765,  6771,  6783,  6784,  6800,  6816,  6823,  6824,  
+    6912,  6916,  6917,  6964,  6965,  6966,  6971,  6972,  6973,  6978,  
+    6979,  6981,  6992,  7002,  7009,  7019,  7028,  7040,  7042,  7043,  
+    7073,  7074,  7078,  7080,  7082,  7083,  7084,  7086,  7088,  7098,  
+    7142,  7143,  7144,  7146,  7149,  7150,  7151,  7154,  7164,  7168,  
+    7204,  7212,  7220,  7222,  7227,  7232,  7245,  7248,  7258,  7288,  
+    7294,  7360,  7376,  7379,  7380,  7393,  7394,  7401,  7405,  7406,  
+    7410,  7412,  7413,  7424,  7468,  7531,  7544,  7545,  7579,  7616,  
+    7676,  7680,  7830,  7838,  7936,  7944,  7952,  7960,  7968,  7976,  
+    7984,  7992,  8000,  8008,  8016,  8025,  8027,  8029,  8031,  8033,  
+    8040,  8048,  8064,  8072,  8080,  8088,  8096,  8104,  8112,  8118,  
+    8120,  8124,  8125,  8126,  8127,  8130,  8134,  8136,  8140,  8141,  
+    8144,  8150,  8152,  8157,  8160,  8168,  8173,  8178,  8182,  8184,  
+    8188,  8189,  8192,  8203,  8208,  8214,  8216,  8217,  8218,  8219,  
+    8221,  8222,  8223,  8224,  8232,  8233,  8234,  8239,  8240,  8249,  
+    8250,  8251,  8255,  8257,  8260,  8261,  8262,  8263,  8274,  8275,  
+    8276,  8277,  8287,  8288,  8298,  8304,  8305,  8308,  8314,  8317,  
+    8318,  8319,  8320,  8330,  8333,  8334,  8336,  8352,  8400,  8413,  
+    8417,  8418,  8421,  8448,  8450,  8451,  8455,  8456,  8458,  8459,  
+    8462,  8464,  8467,  8468,  8469,  8470,  8472,  8473,  8478,  8484,  
+    8485,  8486,  8487,  8488,  8489,  8490,  8494,  8495,  8496,  8500,  
+    8501,  8505,  8506,  8508,  8510,  8512,  8517,  8519,  8522,  8523,  
+    8524,  8526,  8527,  8528,  8544,  8579,  8581,  8585,  8592,  8597,  
+    8602,  8604,  8608,  8609,  8611,  8612,  8614,  8615,  8622,  8623,  
+    8654,  8656,  8658,  8659,  8660,  8661,  8692,  8960,  8968,  8972,  
+    8992,  8994,  9001,  9002,  9003,  9084,  9085,  9115,  9140,  9180,  
+    9186,  9216,  9280,  9312,  9372,  9450,  9472,  9655,  9656,  9665,  
+    9666,  9720,  9728,  9839,  9840,  9985,  10088, 10089, 10090, 10091, 
+    10092, 10093, 10094, 10095, 10096, 10097, 10098, 10099, 10100, 10101, 
+    10102, 10132, 10176, 10181, 10182, 10183, 10214, 10215, 10216, 10217, 
+    10218, 10219, 10220, 10221, 10222, 10223, 10224, 10240, 10496, 10627, 
+    10628, 10629, 10630, 10631, 10632, 10633, 10634, 10635, 10636, 10637, 
+    10638, 10639, 10640, 10641, 10642, 10643, 10644, 10645, 10646, 10647, 
+    10648, 10649, 10712, 10713, 10714, 10715, 10716, 10748, 10749, 10750, 
+    11008, 11056, 11077, 11079, 11088, 11264, 11312, 11360, 11363, 11365, 
+    11367, 11374, 11377, 11378, 11380, 11381, 11383, 11388, 11390, 11393, 
+    11394, 11492, 11493, 11499, 11503, 11506, 11513, 11517, 11518, 11520, 
+    11559, 11565, 11568, 11631, 11632, 11647, 11648, 11680, 11688, 11696, 
+    11704, 11712, 11720, 11728, 11736, 11744, 11776, 11778, 11779, 11780, 
+    11781, 11782, 11785, 11786, 11787, 11788, 11789, 11790, 11799, 11800, 
+    11802, 11803, 11804, 11805, 11806, 11808, 11809, 11810, 11811, 11812, 
+    11813, 11814, 11815, 11816, 11817, 11818, 11823, 11824, 11834, 11904, 
+    11931, 12032, 12272, 12288, 12289, 12292, 12293, 12294, 12295, 12296, 
+    12297, 12298, 12299, 12300, 12301, 12302, 12303, 12304, 12305, 12306, 
+    12308, 12309, 12310, 12311, 12312, 12313, 12314, 12315, 12316, 12317, 
+    12318, 12320, 12321, 12330, 12334, 12336, 12337, 12342, 12344, 12347, 
+    12348, 12349, 12350, 12353, 12441, 12443, 12445, 12447, 12448, 12449, 
+    12539, 12540, 12543, 12549, 12593, 12688, 12690, 12694, 12704, 12736, 
+    12784, 12800, 12832, 12842, 12872, 12880, 12881, 12896, 12928, 12938, 
+    12977, 12992, 13056, 13312, 19893, 19904, 19968, 40908, 40960, 40981, 
+    40982, 42128, 42192, 42232, 42238, 42240, 42508, 42509, 42512, 42528, 
+    42538, 42560, 42606, 42607, 42608, 42611, 42612, 42622, 42623, 42624, 
+    42655, 42656, 42726, 42736, 42738, 42752, 42775, 42784, 42786, 42800, 
+    42802, 42864, 42865, 42873, 42878, 42888, 42889, 42891, 42896, 42912, 
+    43000, 43002, 43003, 43010, 43011, 43014, 43015, 43019, 43020, 43043, 
+    43045, 43047, 43048, 43056, 43062, 43064, 43065, 43072, 43124, 43136, 
+    43138, 43188, 43204, 43214, 43216, 43232, 43250, 43256, 43259, 43264, 
+    43274, 43302, 43310, 43312, 43335, 43346, 43359, 43360, 43392, 43395, 
+    43396, 43443, 43444, 43446, 43450, 43452, 43453, 43457, 43471, 43472, 
+    43486, 43520, 43561, 43567, 43569, 43571, 43573, 43584, 43587, 43588, 
+    43596, 43597, 43600, 43612, 43616, 43632, 43633, 43639, 43642, 43643, 
+    43648, 43696, 43697, 43698, 43701, 43703, 43705, 43710, 43712, 43713, 
+    43714, 43739, 43741, 43742, 43744, 43755, 43756, 43758, 43760, 43762, 
+    43763, 43765, 43766, 43777, 43785, 43793, 43808, 43816, 43968, 44003, 
+    44005, 44006, 44008, 44009, 44011, 44012, 44013, 44016, 44032, 55203, 
+    55216, 55243, 55296, 56191, 56319, 57343, 57344, 63743, 63744, 64112, 
+    64256, 64275, 64285, 64286, 64287, 64297, 64298, 64312, 64318, 64320, 
+    64323, 64326, 64434, 64467, 64830, 64831, 64848, 64914, 65008, 65020, 
+    65021, 65024, 65040, 65047, 65048, 65049, 65056, 65072, 65073, 65075, 
+    65077, 65078, 65079, 65080, 65081, 65082, 65083, 65084, 65085, 65086, 
+    65087, 65088, 65089, 65090, 65091, 65092, 65093, 65095, 65096, 65097, 
+    65101, 65104, 65108, 65112, 65113, 65114, 65115, 65116, 65117, 65118, 
+    65119, 65122, 65123, 65124, 65128, 65129, 65130, 65136, 65142, 65279, 
+    65281, 65284, 65285, 65288, 65289, 65290, 65291, 65292, 65293, 65294, 
+    65296, 65306, 65308, 65311, 65313, 65339, 65340, 65341, 65342, 65343, 
+    65344, 65345, 65371, 65372, 65373, 65374, 65375, 65376, 65377, 65378, 
+    65379, 65380, 65382, 65392, 65393, 65438, 65440, 65474, 65482, 65490, 
+    65498, 65504, 65506, 65507, 65508, 65509, 65512, 65513, 65517, 65529, 
+    65532, 0,     13,    40,    60,    63,    80,    128,   256,   263,   
+    311,   320,   373,   377,   394,   400,   464,   509,   640,   672,   
+    768,   800,   816,   833,   834,   842,   896,   927,   928,   968,   
+    976,   977,   1024,  1064,  1104,  1184,  2048,  2056,  2058,  2103,  
+    2108,  2111,  2135,  2136,  2304,  2326,  2335,  2336,  2367,  2432,  
+    2494,  2560,  2561,  2565,  2572,  2576,  2581,  2585,  2616,  2623,  
+    2624,  2640,  2656,  2685,  2687,  2816,  2873,  2880,  2904,  2912,  
+    2936,  3072,  3680,  4096,  4097,  4098,  4099,  4152,  4167,  4178,  
+    4198,  4224,  4226,  4227,  4272,  4275,  4279,  4281,  4283,  4285,  
+    4286,  4304,  4336,  4352,  4355,  4391,  4396,  4397,  4406,  4416,  
+    4480,  4482,  4483,  4531,  4534,  4543,  4545,  4549,  4560,  5760,  
+    5803,  5804,  5805,  5806,  5808,  5814,  5815,  5824,  8192,  9216,  
+    9328,  12288, 26624, 28416, 28496, 28497, 28559, 28563, 45056, 53248, 
+    53504, 53545, 53605, 53607, 53610, 53613, 53619, 53627, 53635, 53637, 
+    53644, 53674, 53678, 53760, 53826, 53829, 54016, 54112, 54272, 54298, 
+    54324, 54350, 54358, 54376, 54402, 54428, 54430, 54434, 54437, 54441, 
+    54446, 54454, 54459, 54461, 54469, 54480, 54506, 54532, 54535, 54541, 
+    54550, 54558, 54584, 54587, 54592, 54598, 54602, 54610, 54636, 54662, 
+    54688, 54714, 54740, 54766, 54792, 54818, 54844, 54870, 54896, 54922, 
+    54952, 54977, 54978, 55003, 55004, 55010, 55035, 55036, 55061, 55062, 
+    55068, 55093, 55094, 55119, 55120, 55126, 55151, 55152, 55177, 55178, 
+    55184, 55209, 55210, 55235, 55236, 55242, 55246, 60928, 60933, 60961, 
+    60964, 60967, 60969, 60980, 60985, 60987, 60994, 60999, 61001, 61003, 
+    61005, 61009, 61012, 61015, 61017, 61019, 61021, 61023, 61025, 61028, 
+    61031, 61036, 61044, 61049, 61054, 61056, 61067, 61089, 61093, 61099, 
+    61168, 61440, 61488, 61600, 61617, 61633, 61649, 61696, 61712, 61744, 
+    61808, 61926, 61968, 62016, 62032, 62208, 62256, 62263, 62336, 62368, 
+    62406, 62432, 62464, 62528, 62530, 62713, 62720, 62784, 62800, 62971, 
+    63045, 63104, 63232, 0,     42710, 42752, 46900, 46912, 47133, 63488, 
+    1,     32,    256,   0,     65533, 
+  };
+static u16 aFts5UnicodeData[] = {
+    1025,  61,    117,   55,    117,   54,    50,    53,    57,    53,    
+    49,    85,    333,   85,    121,   85,    841,   54,    53,    50,    
+    56,    48,    56,    837,   54,    57,    50,    57,    1057,  61,    
+    53,    151,   58,    53,    56,    58,    39,    52,    57,    34,    
+    58,    56,    58,    57,    79,    56,    37,    85,    56,    47,    
+    39,    51,    111,   53,    745,   57,    233,   773,   57,    261,   
+    1822,  37,    542,   37,    1534,  222,   69,    73,    37,    126,   
+    126,   73,    69,    137,   37,    73,    37,    105,   101,   73,    
+    37,    73,    37,    190,   158,   37,    126,   126,   73,    37,    
+    126,   94,    37,    39,    94,    69,    135,   41,    40,    37,    
+    41,    40,    37,    41,    40,    37,    542,   37,    606,   37,    
+    41,    40,    37,    126,   73,    37,    1886,  197,   73,    37,    
+    73,    69,    126,   105,   37,    286,   2181,  39,    869,   582,   
+    152,   390,   472,   166,   248,   38,    56,    38,    568,   3596,  
+    158,   38,    56,    94,    38,    101,   53,    88,    41,    53,    
+    105,   41,    73,    37,    553,   297,   1125,  94,    37,    105,   
+    101,   798,   133,   94,    57,    126,   94,    37,    1641,  1541,  
+    1118,  58,    172,   75,    1790,  478,   37,    2846,  1225,  38,    
+    213,   1253,  53,    49,    55,    1452,  49,    44,    53,    76,    
+    53,    76,    53,    44,    871,   103,   85,    162,   121,   85,    
+    55,    85,    90,    364,   53,    85,    1031,  38,    327,   684,   
+    333,   149,   71,    44,    3175,  53,    39,    236,   34,    58,    
+    204,   70,    76,    58,    140,   71,    333,   103,   90,    39,    
+    469,   34,    39,    44,    967,   876,   2855,  364,   39,    333,   
+    1063,  300,   70,    58,    117,   38,    711,   140,   38,    300,   
+    38,    108,   38,    172,   501,   807,   108,   53,    39,    359,   
+    876,   108,   42,    1735,  44,    42,    44,    39,    106,   268,   
+    138,   44,    74,    39,    236,   327,   76,    85,    333,   53,    
+    38,    199,   231,   44,    74,    263,   71,    711,   231,   39,    
+    135,   44,    39,    106,   140,   74,    74,    44,    39,    42,    
+    71,    103,   76,    333,   71,    87,    207,   58,    55,    76,    
+    42,    199,   71,    711,   231,   71,    71,    71,    44,    106,   
+    76,    76,    108,   44,    135,   39,    333,   76,    103,   44,    
+    76,    42,    295,   103,   711,   231,   71,    167,   44,    39,    
+    106,   172,   76,    42,    74,    44,    39,    71,    76,    333,   
+    53,    55,    44,    74,    263,   71,    711,   231,   71,    167,   
+    44,    39,    42,    44,    42,    140,   74,    74,    44,    44,    
+    42,    71,    103,   76,    333,   58,    39,    207,   44,    39,    
+    199,   103,   135,   71,    39,    71,    71,    103,   391,   74,    
+    44,    74,    106,   106,   44,    39,    42,    333,   111,   218,   
+    55,    58,    106,   263,   103,   743,   327,   167,   39,    108,   
+    138,   108,   140,   76,    71,    71,    76,    333,   239,   58,    
+    74,    263,   103,   743,   327,   167,   44,    39,    42,    44,    
+    170,   44,    74,    74,    76,    74,    39,    71,    76,    333,   
+    71,    74,    263,   103,   1319,  39,    106,   140,   106,   106,   
+    44,    39,    42,    71,    76,    333,   207,   58,    199,   74,    
+    583,   775,   295,   39,    231,   44,    106,   108,   44,    266,   
+    74,    53,    1543,  44,    71,    236,   55,    199,   38,    268,   
+    53,    333,   85,    71,    39,    71,    39,    39,    135,   231,   
+    103,   39,    39,    71,    135,   44,    71,    204,   76,    39,    
+    167,   38,    204,   333,   135,   39,    122,   501,   58,    53,    
+    122,   76,    218,   333,   335,   58,    44,    58,    44,    58,    
+    44,    54,    50,    54,    50,    74,    263,   1159,  460,   42,    
+    172,   53,    76,    167,   364,   1164,  282,   44,    218,   90,    
+    181,   154,   85,    1383,  74,    140,   42,    204,   42,    76,    
+    74,    76,    39,    333,   213,   199,   74,    76,    135,   108,   
+    39,    106,   71,    234,   103,   140,   423,   44,    74,    76,    
+    202,   44,    39,    42,    333,   106,   44,    90,    1225,  41,    
+    41,    1383,  53,    38,    10631, 135,   231,   39,    135,   1319,  
+    135,   1063,  135,   231,   39,    135,   487,   1831,  135,   2151,  
+    108,   309,   655,   519,   346,   2727,  49,    19847, 85,    551,   
+    61,    839,   54,    50,    2407,  117,   110,   423,   135,   108,   
+    583,   108,   85,    583,   76,    423,   103,   76,    1671,  76,    
+    42,    236,   266,   44,    74,    364,   117,   38,    117,   55,    
+    39,    44,    333,   335,   213,   49,    149,   108,   61,    333,   
+    1127,  38,    1671,  1319,  44,    39,    2247,  935,   108,   138,   
+    76,    106,   74,    44,    202,   108,   58,    85,    333,   967,   
+    167,   1415,  554,   231,   74,    333,   47,    1114,  743,   76,    
+    106,   85,    1703,  42,    44,    42,    236,   44,    42,    44,    
+    74,    268,   202,   332,   44,    333,   333,   245,   38,    213,   
+    140,   42,    1511,  44,    42,    172,   42,    44,    170,   44,    
+    74,    231,   333,   245,   346,   300,   314,   76,    42,    967,   
+    42,    140,   74,    76,    42,    44,    74,    71,    333,   1415,  
+    44,    42,    76,    106,   44,    42,    108,   74,    149,   1159,  
+    266,   268,   74,    76,    181,   333,   103,   333,   967,   198,   
+    85,    277,   108,   53,    428,   42,    236,   135,   44,    135,   
+    74,    44,    71,    1413,  2022,  421,   38,    1093,  1190,  1260,  
+    140,   4830,  261,   3166,  261,   265,   197,   201,   261,   265,   
+    261,   265,   197,   201,   261,   41,    41,    41,    94,    229,   
+    265,   453,   261,   264,   261,   264,   261,   264,   165,   69,    
+    137,   40,    56,    37,    120,   101,   69,    137,   40,    120,   
+    133,   69,    137,   120,   261,   169,   120,   101,   69,    137,   
+    40,    88,    381,   162,   209,   85,    52,    51,    54,    84,    
+    51,    54,    52,    277,   59,    60,    162,   61,    309,   52,    
+    51,    149,   80,    117,   57,    54,    50,    373,   57,    53,    
+    48,    341,   61,    162,   194,   47,    38,    207,   121,   54,    
+    50,    38,    335,   121,   54,    50,    422,   855,   428,   139,   
+    44,    107,   396,   90,    41,    154,   41,    90,    37,    105,   
+    69,    105,   37,    58,    41,    90,    57,    169,   218,   41,    
+    58,    41,    58,    41,    58,    137,   58,    37,    137,   37,    
+    135,   37,    90,    69,    73,    185,   94,    101,   58,    57,    
+    90,    37,    58,    527,   1134,  94,    142,   47,    185,   186,   
+    89,    154,   57,    90,    57,    90,    57,    250,   57,    1018,  
+    89,    90,    57,    58,    57,    1018,  8601,  282,   153,   666,   
+    89,    250,   54,    50,    2618,  57,    986,   825,   1306,  217,   
+    602,   1274,  378,   1935,  2522,  719,   5882,  57,    314,   57,    
+    1754,  281,   3578,  57,    4634,  3322,  54,    50,    54,    50,    
+    54,    50,    54,    50,    54,    50,    54,    50,    54,    50,    
+    975,   1434,  185,   54,    50,    1017,  54,    50,    54,    50,    
+    54,    50,    54,    50,    54,    50,    537,   8218,  4217,  54,    
+    50,    54,    50,    54,    50,    54,    50,    54,    50,    54,    
+    50,    54,    50,    54,    50,    54,    50,    54,    50,    54,    
+    50,    2041,  54,    50,    54,    50,    1049,  54,    50,    8281,  
+    1562,  697,   90,    217,   346,   1513,  1509,  126,   73,    69,    
+    254,   105,   37,    94,    37,    94,    165,   70,    105,   37,    
+    3166,  37,    218,   158,   108,   94,    149,   47,    85,    1221,  
+    37,    37,    1799,  38,    53,    44,    743,   231,   231,   231,   
+    231,   231,   231,   231,   231,   1036,  85,    52,    51,    52,    
+    51,    117,   52,    51,    53,    52,    51,    309,   49,    85,    
+    49,    53,    52,    51,    85,    52,    51,    54,    50,    54,    
+    50,    54,    50,    54,    50,    181,   38,    341,   81,    858,   
+    2874,  6874,  410,   61,    117,   58,    38,    39,    46,    54,    
+    50,    54,    50,    54,    50,    54,    50,    54,    50,    90,    
+    54,    50,    54,    50,    54,    50,    54,    50,    49,    54,    
+    82,    58,    302,   140,   74,    49,    166,   90,    110,   38,    
+    39,    53,    90,    2759,  76,    88,    70,    39,    49,    2887,  
+    53,    102,   39,    1319,  3015,  90,    143,   346,   871,   1178,  
+    519,   1018,  335,   986,   271,   58,    495,   1050,  335,   1274,  
+    495,   2042,  8218,  39,    39,    2074,  39,    39,    679,   38,    
+    36583, 1786,  1287,  198,   85,    8583,  38,    117,   519,   333,   
+    71,    1502,  39,    44,    107,   53,    332,   53,    38,    798,   
+    44,    2247,  334,   76,    213,   760,   294,   88,    478,   69,    
+    2014,  38,    261,   190,   350,   38,    88,    158,   158,   382,   
+    70,    37,    231,   44,    103,   44,    135,   44,    743,   74,    
+    76,    42,    154,   207,   90,    55,    58,    1671,  149,   74,    
+    1607,  522,   44,    85,    333,   588,   199,   117,   39,    333,   
+    903,   268,   85,    743,   364,   74,    53,    935,   108,   42,    
+    1511,  44,    74,    140,   74,    44,    138,   437,   38,    333,   
+    85,    1319,  204,   74,    76,    74,    76,    103,   44,    263,   
+    44,    42,    333,   149,   519,   38,    199,   122,   39,    42,    
+    1543,  44,    39,    108,   71,    76,    167,   76,    39,    44,    
+    39,    71,    38,    85,    359,   42,    76,    74,    85,    39,    
+    70,    42,    44,    199,   199,   199,   231,   231,   1127,  74,    
+    44,    74,    44,    74,    53,    42,    44,    333,   39,    39,    
+    743,   1575,  36,    68,    68,    36,    63,    63,    11719, 3399,  
+    229,   165,   39,    44,    327,   57,    423,   167,   39,    71,    
+    71,    3463,  536,   11623, 54,    50,    2055,  1735,  391,   55,    
+    58,    524,   245,   54,    50,    53,    236,   53,    81,    80,    
+    54,    50,    54,    50,    54,    50,    54,    50,    54,    50,    
+    54,    50,    54,    50,    54,    50,    85,    54,    50,    149,   
+    112,   117,   149,   49,    54,    50,    54,    50,    54,    50,    
+    117,   57,    49,    121,   53,    55,    85,    167,   4327,  34,    
+    117,   55,    117,   54,    50,    53,    57,    53,    49,    85,    
+    333,   85,    121,   85,    841,   54,    53,    50,    56,    48,    
+    56,    837,   54,    57,    50,    57,    54,    50,    53,    54,    
+    50,    85,    327,   38,    1447,  70,    999,   199,   199,   199,   
+    103,   87,    57,    56,    58,    87,    58,    153,   90,    98,    
+    90,    391,   839,   615,   71,    487,   455,   3943,  117,   1455,  
+    314,   1710,  143,   570,   47,    410,   1466,  44,    935,   1575,  
+    999,   143,   551,   46,    263,   46,    967,   53,    1159,  263,   
+    53,    174,   1289,  1285,  2503,  333,   199,   39,    1415,  71,    
+    39,    743,   53,    271,   711,   207,   53,    839,   53,    1799,  
+    71,    39,    108,   76,    140,   135,   103,   871,   108,   44,    
+    271,   309,   935,   79,    53,    1735,  245,   711,   271,   615,   
+    271,   2343,  1007,  42,    44,    42,    1703,  492,   245,   655,   
+    333,   76,    42,    1447,  106,   140,   74,    76,    85,    34,    
+    149,   807,   333,   108,   1159,  172,   42,    268,   333,   149,   
+    76,    42,    1543,  106,   300,   74,    135,   149,   333,   1383,  
+    44,    42,    44,    74,    204,   42,    44,    333,   28135, 3182,  
+    149,   34279, 18215, 2215,  39,    1482,  140,   422,   71,    7898,  
+    1274,  1946,  74,    108,   122,   202,   258,   268,   90,    236,   
+    986,   140,   1562,  2138,  108,   58,    2810,  591,   841,   837,   
+    841,   229,   581,   841,   837,   41,    73,    41,    73,    137,   
+    265,   133,   37,    229,   357,   841,   837,   73,    137,   265,   
+    233,   837,   73,    137,   169,   41,    233,   837,   841,   837,   
+    841,   837,   841,   837,   841,   837,   841,   837,   841,   901,   
+    809,   57,    805,   57,    197,   809,   57,    805,   57,    197,   
+    809,   57,    805,   57,    197,   809,   57,    805,   57,    197,   
+    809,   57,    805,   57,    197,   94,    1613,  135,   871,   71,    
+    39,    39,    327,   135,   39,    39,    39,    39,    39,    39,    
+    103,   71,    39,    39,    39,    39,    39,    39,    71,    39,    
+    135,   231,   135,   135,   39,    327,   551,   103,   167,   551,   
+    89,    1434,  3226,  506,   474,   506,   506,   367,   1018,  1946,  
+    1402,  954,   1402,  314,   90,    1082,  218,   2266,  666,   1210,  
+    186,   570,   2042,  58,    5850,  154,   2010,  154,   794,   2266,  
+    378,   2266,  3738,  39,    39,    39,    39,    39,    39,    17351, 
+    34,    3074,  7692,  63,    63,    
+  };
+
+static int sqlite3Fts5UnicodeCategory(int iCode) { 
+  int iRes = -1;
+  int iHi;
+  int iLo;
+  int ret;
+  u16 iKey;
+
+  if( iCode>=(1<<20) ){
+    return 0;
+  }
+  iLo = aFts5UnicodeBlock[(iCode>>16)];
+  iHi = aFts5UnicodeBlock[1+(iCode>>16)];
+  iKey = (iCode & 0xFFFF);
+  while( iHi>iLo ){
+    int iTest = (iHi + iLo) / 2;
+    assert( iTest>=iLo && iTest<iHi );
+    if( iKey>=aFts5UnicodeMap[iTest] ){
+      iRes = iTest;
+      iLo = iTest+1;
+    }else{
+      iHi = iTest;
+    }
+  }
+
+  if( iRes<0 ) return 0;
+  if( iKey>=(aFts5UnicodeMap[iRes]+(aFts5UnicodeData[iRes]>>5)) ) return 0;
+  ret = aFts5UnicodeData[iRes] & 0x1F;
+  if( ret!=30 ) return ret;
+  return ((iKey - aFts5UnicodeMap[iRes]) & 0x01) ? 5 : 9;
+}
+
+static void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){
+  int i = 0;
+  int iTbl = 0;
+  while( i<128 ){
+    int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ];
+    int n = (aFts5UnicodeData[iTbl] >> 5) + i;
+    for(; i<128 && i<n; i++){
+      aAscii[i] = (u8)bToken;
+    }
+    iTbl++;
+  }
+}
+
+
 /*
 ** 2015 May 30
 **
@@ -211855,9 +219134,9 @@ SQLITE_API int sqlite3_stmt_init(
 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
 
 /************** End of stmt.c ************************************************/
-#if __LINE__!=211858
+#if __LINE__!=219137
 #undef SQLITE_SOURCE_ID
-#define SQLITE_SOURCE_ID      "2018-06-04 19:24:41 c7ee0833225bfd8c5ec2f9bf62b97c4e04d03bd9566366d5221ac8fb199aalt2"
+#define SQLITE_SOURCE_ID      "2018-09-18 20:20:44 2ac9003de44da7dafa3fbb1915ac5725a9275c86bf2f3b7aa19321bf1460alt2"
 #endif
 /* Return the source-id for this library */
 SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
index 4427d2fa2753b8049dbb829645bbd5fc846eebe1..fe82824324882d97e6549915a7d74e0428c7c0a8 100644 (file)
@@ -123,9 +123,9 @@ extern "C" {
 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
 ** [sqlite_version()] and [sqlite_source_id()].
 */
-#define SQLITE_VERSION        "3.24.0"
-#define SQLITE_VERSION_NUMBER 3024000
-#define SQLITE_SOURCE_ID      "2018-06-04 19:24:41 c7ee0833225bfd8c5ec2f9bf62b97c4e04d03bd9566366d5221ac8fb199a87ca"
+#define SQLITE_VERSION        "3.25.1"
+#define SQLITE_VERSION_NUMBER 3025001
+#define SQLITE_SOURCE_ID      "2018-09-18 20:20:44 2ac9003de44da7dafa3fbb1915ac5725a9275c86bf2f3b7aa19321bf1460b386"
 
 /*
 ** CAPI3REF: Run-Time Library Version Numbers
@@ -472,6 +472,7 @@ SQLITE_API int sqlite3_exec(
 */
 #define SQLITE_ERROR_MISSING_COLLSEQ   (SQLITE_ERROR | (1<<8))
 #define SQLITE_ERROR_RETRY             (SQLITE_ERROR | (2<<8))
+#define SQLITE_ERROR_SNAPSHOT          (SQLITE_ERROR | (3<<8))
 #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))
@@ -511,6 +512,7 @@ SQLITE_API int sqlite3_exec(
 #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_CANTOPEN_DIRTYWAL       (SQLITE_CANTOPEN | (5<<8)) /* Not Used */
 #define SQLITE_CORRUPT_VTAB            (SQLITE_CORRUPT | (1<<8))
 #define SQLITE_CORRUPT_SEQUENCE        (SQLITE_CORRUPT | (2<<8))
 #define SQLITE_READONLY_RECOVERY       (SQLITE_READONLY | (1<<8))
@@ -886,7 +888,8 @@ struct sqlite3_io_methods {
 ** <li>[[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
+** write ahead log ([WAL file]) 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
@@ -1072,6 +1075,26 @@ struct sqlite3_io_methods {
 ** a file lock using the xLock or xShmLock methods of the VFS to wait
 ** for up to M milliseconds before failing, where M is the single 
 ** unsigned integer parameter.
+**
+** <li>[[SQLITE_FCNTL_DATA_VERSION]]
+** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to
+** a database file.  The argument is a pointer to a 32-bit unsigned integer.
+** The "data version" for the pager is written into the pointer.  The
+** "data version" changes whenever any change occurs to the corresponding
+** database file, either through SQL statements on the same database
+** connection or through transactions committed by separate database
+** connections possibly in other processes. The [sqlite3_total_changes()]
+** interface can be used to find if any database on the connection has changed,
+** but that interface responds to changes on TEMP as well as MAIN and does
+** not provide a mechanism to detect changes to MAIN only.  Also, the
+** [sqlite3_total_changes()] interface responds to internal changes only and
+** omits changes made by other database connections.  The
+** [PRAGMA data_version] command provide a mechanism to detect changes to
+** a single attached database that occur due to other database connections,
+** but omits changes implemented by the database connection on which it is
+** called.  This file control is the only mechanism to detect changes that
+** happen either internally or externally and that are associated with
+** a particular attached database.
 ** </ul>
 */
 #define SQLITE_FCNTL_LOCKSTATE               1
@@ -1107,6 +1130,7 @@ struct sqlite3_io_methods {
 #define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE    32
 #define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE  33
 #define SQLITE_FCNTL_LOCK_TIMEOUT           34
+#define SQLITE_FCNTL_DATA_VERSION           35
 
 /* deprecated names */
 #define SQLITE_GET_LOCKPROXYFILE      SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -2121,6 +2145,12 @@ struct sqlite3_mem_methods {
 ** with no schema and no content. The following process works even for
 ** a badly corrupted database file:
 ** <ol>
+** <li> If the database connection is newly opened, make sure it has read the
+**      database schema by preparing then discarding some query against the
+**      database, or calling sqlite3_table_column_metadata(), ignoring any
+**      errors.  This step is only necessary if the application desires to keep
+**      the database in WAL mode after the reset if it was in WAL mode before
+**      the reset.  
 ** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
 ** <li> [sqlite3_exec](db, "[VACUUM]", 0, 0, 0);
 ** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
@@ -2269,12 +2299,17 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
 ** 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.
+**
+** See also:
+** <ul>
+** <li> the [sqlite3_total_changes()] interface
+** <li> the [count_changes pragma]
+** <li> the [changes() SQL function]
+** <li> the [data_version pragma]
+** </ul>
 */
 SQLITE_API int sqlite3_changes(sqlite3*);
 
@@ -2292,13 +2327,26 @@ SQLITE_API int sqlite3_changes(sqlite3*);
 ** 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].
 **
+** This the [sqlite3_total_changes(D)] interface only reports the number
+** of rows that changed due to SQL statement run against database
+** connection D.  Any changes by other database connections are ignored.
+** To detect changes against a database file from other database
+** connections use the [PRAGMA data_version] command or the
+** [SQLITE_FCNTL_DATA_VERSION] [file control].
+** 
 ** If a separate thread makes changes on the same database connection
 ** while [sqlite3_total_changes()] is running then the value
 ** returned is unpredictable and not meaningful.
+**
+** See also:
+** <ul>
+** <li> the [sqlite3_changes()] interface
+** <li> the [count_changes pragma]
+** <li> the [changes() SQL function]
+** <li> the [data_version pragma]
+** <li> the [SQLITE_FCNTL_DATA_VERSION] [file control]
+** </ul>
 */
 SQLITE_API int sqlite3_total_changes(sqlite3*);
 
@@ -3354,13 +3402,24 @@ SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int
 ** [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 values returned by sqlite3_errcode() and/or
+** sqlite3_extended_errcode() might change with each API call.
+** Except, there are some interfaces that are guaranteed to never
+** change the value of the error code.  The error-code preserving
+** interfaces are:
+**
+** <ul>
+** <li> sqlite3_errcode()
+** <li> sqlite3_extended_errcode()
+** <li> sqlite3_errmsg()
+** <li> sqlite3_errmsg16()
+** </ul>
+**
 ** ^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.
@@ -4514,11 +4573,25 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
 ** 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].)^
+** As long as the input parameters are correct, these routines will only
+** fail if an out-of-memory error occurs during a format conversion.
+** Only the following subset of interfaces are subject to out-of-memory
+** errors:
+**
+** <ul>
+** <li> sqlite3_column_blob()
+** <li> sqlite3_column_text()
+** <li> sqlite3_column_text16()
+** <li> sqlite3_column_bytes()
+** <li> sqlite3_column_bytes16()
+** </ul>
+**
+** If an out-of-memory error occurs, then the return value from these
+** routines is the same as if the column had contained an SQL NULL value.
+** Valid SQL NULL returns can be distinguished from out-of-memory errors
+** by invoking the [sqlite3_errcode()] immediately after the suspect
+** return value is obtained and before any
+** other SQLite interface is called on the same [database connection].
 */
 SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
 SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol);
@@ -4595,11 +4668,13 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
 **
 ** ^These functions (collectively known as "function creation routines")
 ** are used to add SQL functions or aggregates or to redefine the behavior
-** of existing SQL functions or aggregates.  The only differences between
-** 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.
+** of existing SQL functions or aggregates. The only differences between
+** the three "sqlite3_create_function*" routines are the text encoding 
+** expected for the second parameter (the name of the function being 
+** created) and the presence or absence of a destructor callback for
+** the application data pointer. Function sqlite3_create_window_function()
+** is similar, but allows the user to supply the extra callback functions
+** needed by [aggregate window functions].
 **
 ** ^The first parameter is the [database connection] to which the SQL
 ** function is to be added.  ^If an application uses more than one database
@@ -4645,7 +4720,8 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
 ** ^(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
+** ^The sixth, seventh and eighth parameters passed to the three
+** "sqlite3_create_function*" functions, 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
@@ -4654,15 +4730,24 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
 ** 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().
+** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue 
+** and xInverse) passed to sqlite3_create_window_function are pointers to
+** C-language callbacks that implement the new function. xStep and xFinal
+** must both be non-NULL. xValue and xInverse may either both be NULL, in
+** which case a regular aggregate function is created, or must both be 
+** non-NULL, in which case the new function may be used as either an aggregate
+** or aggregate window function. More details regarding the implementation
+** of aggregate window functions are 
+** [user-defined window functions|available here].
+**
+** ^(If the final parameter to sqlite3_create_function_v2() or
+** sqlite3_create_window_function() is not NULL, then it is destructor for
+** the application data pointer. The destructor is invoked when the function 
+** is deleted, either by being overloaded or when the database connection 
+** closes.)^ ^The destructor is also invoked if the call to 
+** sqlite3_create_function_v2() fails.  ^When the destructor callback is
+** invoked, it is passed a single argument which is a copy of the application
+** data pointer which was the fifth parameter to sqlite3_create_function_v2().
 **
 ** ^It is permitted to register multiple implementations of the same
 ** functions with the same name but with either differing numbers of
@@ -4715,6 +4800,18 @@ SQLITE_API int sqlite3_create_function_v2(
   void (*xFinal)(sqlite3_context*),
   void(*xDestroy)(void*)
 );
+SQLITE_API int sqlite3_create_window_function(
+  sqlite3 *db,
+  const char *zFunctionName,
+  int nArg,
+  int eTextRep,
+  void *pApp,
+  void (*xStep)(sqlite3_context*,int,sqlite3_value**),
+  void (*xFinal)(sqlite3_context*),
+  void (*xValue)(sqlite3_context*),
+  void (*xInverse)(sqlite3_context*,int,sqlite3_value**),
+  void(*xDestroy)(void*)
+);
 
 /*
 ** CAPI3REF: Text Encodings
@@ -4857,6 +4954,28 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
 **
 ** These routines must be called from the same thread as
 ** the SQL function that supplied the [sqlite3_value*] parameters.
+**
+** As long as the input parameter is correct, these routines can only
+** fail if an out-of-memory error occurs during a format conversion.
+** Only the following subset of interfaces are subject to out-of-memory
+** errors:
+**
+** <ul>
+** <li> sqlite3_value_blob()
+** <li> sqlite3_value_text()
+** <li> sqlite3_value_text16()
+** <li> sqlite3_value_text16le()
+** <li> sqlite3_value_text16be()
+** <li> sqlite3_value_bytes()
+** <li> sqlite3_value_bytes16()
+** </ul>
+**
+** If an out-of-memory error occurs, then the return value from these
+** routines is the same as if the column had contained an SQL NULL value.
+** Valid SQL NULL returns can be distinguished from out-of-memory errors
+** by invoking the [sqlite3_errcode()] immediately after the suspect
+** return value is obtained and before any
+** other SQLite interface is called on the same [database connection].
 */
 SQLITE_API const void *sqlite3_value_blob(sqlite3_value*);
 SQLITE_API double sqlite3_value_double(sqlite3_value*);
@@ -6323,6 +6442,7 @@ struct sqlite3_index_info {
 #define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
 #define SQLITE_INDEX_CONSTRAINT_ISNULL    71
 #define SQLITE_INDEX_CONSTRAINT_IS        72
+#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150
 
 /*
 ** CAPI3REF: Register A Virtual Table Implementation
@@ -6999,6 +7119,7 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
 /*
 ** CAPI3REF: Low-Level Control Of Database Files
 ** METHOD: sqlite3
+** KEYWORDS: {file control}
 **
 ** ^The [sqlite3_file_control()] interface makes a direct call to the
 ** xFileControl method for the [sqlite3_io_methods] object associated
@@ -7013,11 +7134,18 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
 ** the xFileControl method.  ^The return value of the xFileControl
 ** method becomes the return value of this routine.
 **
+** A few opcodes for [sqlite3_file_control()] are handled directly
+** by the SQLite core and never invoke the 
+** sqlite3_io_methods.xFileControl method.
 ** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes
 ** a pointer to the underlying [sqlite3_file] object to be written into
-** 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.
+** the space pointed to by the 4th parameter.  The
+** [SQLITE_FCNTL_JOURNAL_POINTER] works similarly except that it returns
+** the [sqlite3_file] object associated with the journal file instead of
+** the main database.  The [SQLITE_FCNTL_VFS_POINTER] opcode returns
+** a pointer to the underlying [sqlite3_vfs] object for the file.
+** The [SQLITE_FCNTL_DATA_VERSION] returns the data version counter
+** from the pager.
 **
 ** ^If the second parameter (zDbName) does not match the name of any
 ** open database file, then SQLITE_ERROR is returned.  ^This error
@@ -8836,7 +8964,6 @@ 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.
@@ -8853,11 +8980,6 @@ SQLITE_API int sqlite3_system_errno(sqlite3*);
 ** 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];
@@ -8865,7 +8987,7 @@ typedef struct sqlite3_snapshot {
 
 /*
 ** CAPI3REF: Record A Database Snapshot
-** EXPERIMENTAL
+** CONSTRUCTOR: sqlite3_snapshot
 **
 ** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a
 ** new [sqlite3_snapshot] object that records the current state of
@@ -8881,7 +9003,7 @@ typedef struct sqlite3_snapshot {
 ** in this case. 
 **
 ** <ul>
-**   <li> The database handle must be in [autocommit mode].
+**   <li> The database handle must not be in [autocommit mode].
 **
 **   <li> Schema S of [database connection] D must be a [WAL mode] database.
 **
@@ -8904,7 +9026,7 @@ typedef struct sqlite3_snapshot {
 ** to avoid a memory leak.
 **
 ** The [sqlite3_snapshot_get()] interface is only available when the
-** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
+** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used.
 */
 SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
   sqlite3 *db,
@@ -8914,24 +9036,35 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
 
 /*
 ** CAPI3REF: Start a read transaction on an historical snapshot
-** EXPERIMENTAL
+** METHOD: sqlite3_snapshot
+**
+** ^The [sqlite3_snapshot_open(D,S,P)] interface either starts a new read 
+** transaction or upgrades an existing one for schema S of 
+** [database connection] D such that the read transaction refers to 
+** historical [snapshot] P, rather than the most recent change to the 
+** database. ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK 
+** on success or an appropriate [error code] if it fails.
+**
+** ^In order to succeed, the database connection must not be in 
+** [autocommit mode] when [sqlite3_snapshot_open(D,S,P)] is called. If there
+** is already a read transaction open on schema S, then the database handle
+** must have no active statements (SELECT statements that have been passed
+** to sqlite3_step() but not sqlite3_reset() or sqlite3_finalize()). 
+** SQLITE_ERROR is returned if either of these conditions is violated, or
+** if schema S does not exist, or if the snapshot object is invalid.
+**
+** ^A call to sqlite3_snapshot_open() will fail to open if the specified
+** snapshot has been overwritten by a [checkpoint]. In this case 
+** SQLITE_ERROR_SNAPSHOT is returned.
+**
+** If there is already a read transaction open when this function is 
+** invoked, then the same read transaction remains open (on the same
+** database snapshot) if SQLITE_ERROR, SQLITE_BUSY or SQLITE_ERROR_SNAPSHOT
+** is returned. If another error code - for example SQLITE_PROTOCOL or an
+** SQLITE_IOERR error code - is returned, then the final state of the
+** read transaction is undefined. If SQLITE_OK is returned, then the 
+** read transaction is now open on database snapshot P.
 **
-** ^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
@@ -8942,7 +9075,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
 ** 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_ENABLE_SNAPSHOT] compile-time option is used.
 */
 SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open(
   sqlite3 *db,
@@ -8952,20 +9085,20 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open(
 
 /*
 ** CAPI3REF: Destroy a snapshot
-** EXPERIMENTAL
+** DESTRUCTOR: sqlite3_snapshot
 **
 ** ^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_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
+** METHOD: sqlite3_snapshot
 **
 ** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages
 ** of two valid snapshot handles. 
@@ -8984,6 +9117,9 @@ SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*);
 ** 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.
+**
+** This interface is only available if SQLite is compiled with the
+** [SQLITE_ENABLE_SNAPSHOT] option.
 */
 SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
   sqlite3_snapshot *p1,
@@ -8992,23 +9128,26 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
 
 /*
 ** CAPI3REF: Recover snapshots from a wal file
-** EXPERIMENTAL
+** METHOD: sqlite3_snapshot
 **
-** 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.
+** If a [WAL file] remains on disk after all database connections close
+** (either through the use of the [SQLITE_FCNTL_PERSIST_WAL] [file control]
+** or because the last process to have the database opened exited without
+** calling [sqlite3_close()]) and a new connection is subsequently opened
+** on that database and [WAL file], the [sqlite3_snapshot_open()] interface
+** will only be able to open the last transaction added to the WAL file
+** even though the WAL file contains other valid transactions.
 **
-** This function attempts to scan the wal file associated with database zDb
+** 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
+** 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.
+**
+** This interface is only available if SQLite is compiled with the
+** [SQLITE_ENABLE_SNAPSHOT] option.
 */
 SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
 
@@ -9119,7 +9258,7 @@ SQLITE_API int sqlite3_deserialize(
 ** in the P argument is held in memory obtained from [sqlite3_malloc64()]
 ** and that SQLite should take ownership of this memory and automatically
 ** free it when it has finished using it.  Without this flag, the caller
-** is resposible for freeing any dynamically allocated memory.
+** is responsible for freeing any dynamically allocated memory.
 **
 ** The SQLITE_DESERIALIZE_RESIZEABLE flag means that SQLite is allowed to
 ** grow the size of the database using calls to [sqlite3_realloc64()].  This
@@ -11297,7 +11436,7 @@ struct Fts5ExtensionApi {
 **            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
+**            'first + place' or '1st + place', as there are entries in the
 **            FTS index corresponding to both forms of the first token.
 **   </ol>
 **
@@ -11325,7 +11464,7 @@ struct Fts5ExtensionApi {
 **   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:
+**   token "first" is substituted for "1st" by the tokenizer, then the query:
 **
 **   <codeblock>
 **     ... MATCH '1s*'</codeblock>