]> git.lizzy.rs Git - sqlite3-cmake.git/commitdiff
sqlite 3.9.0 enable FTS5 and JSON
authoralex85k <alex85k@github.com>
Thu, 15 Oct 2015 15:45:30 +0000 (20:45 +0500)
committeralex85k <alex85k@github.com>
Thu, 15 Oct 2015 15:45:30 +0000 (20:45 +0500)
CMakeLists.txt
src/shell.c
src/sqlite3.c
src/sqlite3.h
src/sqlite3ext.h

index b47c6ccdebfb20811457b2da88b2d9d75cad5669..45c59b662210cc223b3ed0a782a783e9d58d71ab 100644 (file)
@@ -8,6 +8,8 @@ set_target_properties(sqlite PROPERTIES OUTPUT_NAME sqlite3)
 
 add_definitions(-DSQLITE_ENABLE_RTREE)
 add_definitions(-DSQLITE_ENABLE_FTS4)
+add_definitions(-DSQLITE_ENABLE_FTS5)
+add_definitions(-DSQLITE_ENABLE_JSON1)
 
 install(FILES src/sqlite3.h src/sqlite3ext.h DESTINATION include)
 install(TARGETS sqlite3 LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
index d097e913a3b43cc2466522f83218fa07d75b411b..f79087122c1235926ea626965cd3d4a6a27bfc5c 100644 (file)
@@ -1319,6 +1319,8 @@ static int display_stats(
     fprintf(pArg->out, "Virtual Machine Steps:               %d\n", iCur);
   }
 
+  /* Do not remove this machine readable comment: extra-stats-output-here */
+
   return 0;
 }
 
@@ -2610,6 +2612,22 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
   return 0;
 }
 
+/*
+** Print the current sqlite3_errmsg() value to stderr and return 1.
+*/
+static int shellDatabaseError(sqlite3 *db){
+  const char *zErr = sqlite3_errmsg(db);
+  fprintf(stderr, "Error: %s\n", zErr);
+  return 1;
+}
+
+/*
+** Print an out-of-memory message to stderr and return 1.
+*/
+static int shellNomemError(void){
+  fprintf(stderr, "Error: out of memory\n");
+  return 1;
+}
 
 /*
 ** If an input line begins with "." then invoke this routine to
@@ -3711,13 +3729,17 @@ static int do_meta_command(char *zLine, ShellState *p){
     int ii;
     open_db(p, 0);
     rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
-    if( rc ) return rc;
+    if( rc ) return shellDatabaseError(p->db);
+
+    /* Create an SQL statement to query for the list of tables in the
+    ** main and all attached databases where the table name matches the
+    ** LIKE pattern bound to variable "?1". */
     zSql = sqlite3_mprintf(
         "SELECT name FROM sqlite_master"
         " WHERE type IN ('table','view')"
         "   AND name NOT LIKE 'sqlite_%%'"
         "   AND name LIKE ?1");
-    while( sqlite3_step(pStmt)==SQLITE_ROW ){
+    while( zSql && sqlite3_step(pStmt)==SQLITE_ROW ){
       const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1);
       if( zDbName==0 || strcmp(zDbName,"main")==0 ) continue;
       if( strcmp(zDbName,"temp")==0 ){
@@ -3736,11 +3758,17 @@ static int do_meta_command(char *zLine, ShellState *p){
                  "   AND name LIKE ?1", zSql, zDbName, zDbName);
       }
     }
-    sqlite3_finalize(pStmt);
-    zSql = sqlite3_mprintf("%z ORDER BY 1", zSql);
-    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+    rc = sqlite3_finalize(pStmt);
+    if( zSql && rc==SQLITE_OK ){
+      zSql = sqlite3_mprintf("%z ORDER BY 1", zSql);
+      if( zSql ) rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
+    }
     sqlite3_free(zSql);
-    if( rc ) return rc;
+    if( !zSql ) return shellNomemError();
+    if( rc ) return shellDatabaseError(p->db);
+
+    /* Run the SQL statement prepared by the above block. Store the results
+    ** as an array of nul-terminated strings in azResult[].  */
     nRow = nAlloc = 0;
     azResult = 0;
     if( nArg>1 ){
@@ -3754,17 +3782,25 @@ static int do_meta_command(char *zLine, ShellState *p){
         int n2 = nAlloc*2 + 10;
         azNew = sqlite3_realloc64(azResult, sizeof(azResult[0])*n2);
         if( azNew==0 ){
-          fprintf(stderr, "Error: out of memory\n");
+          rc = shellNomemError();
           break;
         }
         nAlloc = n2;
         azResult = azNew;
       }
       azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0));
-      if( azResult[nRow] ) nRow++;
+      if( 0==azResult[nRow] ){
+        rc = shellNomemError();
+        break;
+      }
+      nRow++;
+    }
+    if( sqlite3_finalize(pStmt)!=SQLITE_OK ){
+      rc = shellDatabaseError(p->db);
     }
-    sqlite3_finalize(pStmt);        
-    if( nRow>0 ){
+
+    /* Pretty-print the contents of array azResult[] to the output */
+    if( rc==0 && nRow>0 ){
       int len, maxlen = 0;
       int i, j;
       int nPrintCol, nPrintRow;
@@ -3783,6 +3819,7 @@ static int do_meta_command(char *zLine, ShellState *p){
         fprintf(p->out, "\n");
       }
     }
+
     for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]);
     sqlite3_free(azResult);
   }else
@@ -4250,8 +4287,8 @@ static int process_input(ShellState *p, FILE *in){
       fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
       errCnt++;
     }
-    free(zSql);
   }
+  free(zSql);
   free(zLine);
   return errCnt>0;
 }
index 1344938873b4ec0840afde73908e47a18bfc7a58..ac3ef3915120f1ce3448ce87719c51ac6c1caf2d 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
 ** This file is an amalgamation of many separate C source files from SQLite
-** version 3.8.11.1.  By combining all the individual C code files into this 
+** version 3.9.0.  By combining all the individual C code files into this 
 ** single large file, the entire code can be compiled as a single translation
 ** unit.  This allows many compilers to do optimizations that would not be
 ** possible if the files were compiled separately.  Performance improvements
@@ -325,9 +325,9 @@ extern "C" {
 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
 ** [sqlite_version()] and [sqlite_source_id()].
 */
-#define SQLITE_VERSION        "3.8.11.1"
-#define SQLITE_VERSION_NUMBER 3008011
-#define SQLITE_SOURCE_ID      "2015-07-29 20:00:57 cf538e2783e468bbc25e7cb2a9ee64d3e0e80b2f"
+#define SQLITE_VERSION        "3.9.0"
+#define SQLITE_VERSION_NUMBER 3009000
+#define SQLITE_SOURCE_ID      "2015-10-14 12:29:53 a721fc0d89495518fe5612e2e3bbc60befd2e90d"
 
 /*
 ** CAPI3REF: Run-Time Library Version Numbers
@@ -338,7 +338,7 @@ extern "C" {
 ** but are associated with the library instead of the header file.  ^(Cautious
 ** programmers might include assert() statements in their application to
 ** verify that values returned by these interfaces match the macros in
-** the header, and thus insure that the application is
+** the header, and thus ensure that the application is
 ** compiled with matching library and header files.
 **
 ** <blockquote><pre>
@@ -588,7 +588,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
 ** Restrictions:
 **
 ** <ul>
-** <li> The application must insure that the 1st parameter to sqlite3_exec()
+** <li> The application must ensure that the 1st parameter to sqlite3_exec()
 **      is a valid and open [database connection].
 ** <li> The application must not close the [database connection] specified by
 **      the 1st parameter to sqlite3_exec() while sqlite3_exec() is running.
@@ -691,6 +691,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
 #define SQLITE_IOERR_MMAP              (SQLITE_IOERR | (24<<8))
 #define SQLITE_IOERR_GETTEMPPATH       (SQLITE_IOERR | (25<<8))
 #define SQLITE_IOERR_CONVPATH          (SQLITE_IOERR | (26<<8))
+#define SQLITE_IOERR_VNODE             (SQLITE_IOERR | (27<<8))
 #define SQLITE_LOCKED_SHAREDCACHE      (SQLITE_LOCKED |  (1<<8))
 #define SQLITE_BUSY_RECOVERY           (SQLITE_BUSY   |  (1<<8))
 #define SQLITE_BUSY_SNAPSHOT           (SQLITE_BUSY   |  (2<<8))
@@ -1580,9 +1581,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void);
 ** applications and so this routine is usually not necessary.  It is
 ** provided to support rare applications with unusual needs.
 **
-** The sqlite3_config() interface is not threadsafe.  The application
-** must insure that no other SQLite interfaces are invoked by other
-** threads while sqlite3_config() is running.  Furthermore, sqlite3_config()
+** <b>The sqlite3_config() interface is not threadsafe. The application
+** must ensure that no other SQLite interfaces are invoked by other
+** threads while sqlite3_config() is running.</b>
+**
+** The sqlite3_config() interface
 ** may only be invoked prior to library initialization using
 ** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()].
 ** ^If sqlite3_config() is called after [sqlite3_initialize()] and before
@@ -3587,7 +3590,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
 **
 ** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the
 ** [prepared statement] S has been stepped at least once using 
-** [sqlite3_step(S)] but has not run to completion and/or has not 
+** [sqlite3_step(S)] but has neither run to completion (returned
+** [SQLITE_DONE] from [sqlite3_step(S)]) nor
 ** been reset using [sqlite3_reset(S)].  ^The sqlite3_stmt_busy(S)
 ** interface returns false if S is a NULL pointer.  If S is not a 
 ** NULL pointer and is not a pointer to a valid [prepared statement]
@@ -3840,7 +3844,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*,
 **
 ** See also: [sqlite3_bind_blob|sqlite3_bind()],
 ** [sqlite3_bind_parameter_count()], and
-** [sqlite3_bind_parameter_index()].
+** [sqlite3_bind_parameter_name()].
 */
 SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
 
@@ -4569,6 +4573,22 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16be(sqlite3_value*);
 SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value*);
 SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*);
 
+/*
+** CAPI3REF: Finding The Subtype Of SQL Values
+** METHOD: sqlite3_value
+**
+** The sqlite3_value_subtype(V) function returns the subtype for
+** an [application-defined SQL function] argument V.  The subtype
+** information can be used to pass a limited amount of context from
+** one SQL function to another.  Use the [sqlite3_result_subtype()]
+** routine to set the subtype for the return value of an SQL function.
+**
+** SQLite makes no use of subtype itself.  It merely passes the subtype
+** from the result of one [application-defined SQL function] into the
+** input of another.
+*/
+SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value*);
+
 /*
 ** CAPI3REF: Copy And Free SQL Values
 ** METHOD: sqlite3_value
@@ -4868,6 +4888,21 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context*, sqlite3_va
 SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context*, int n);
 SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
 
+
+/*
+** CAPI3REF: Setting The Subtype Of An SQL Function
+** METHOD: sqlite3_context
+**
+** The sqlite3_result_subtype(C,T) function causes the subtype of
+** the result from the [application-defined SQL function] with 
+** [sqlite3_context] C to be the value T.  Only the lower 8 bits 
+** of the subtype T are preserved in current versions of SQLite;
+** higher order bits are discarded.
+** The number of subtype bytes preserved by SQLite might increase
+** in future releases of SQLite.
+*/
+SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context*,unsigned int);
+
 /*
 ** CAPI3REF: Define New Collating Sequences
 ** METHOD: sqlite3
@@ -5813,13 +5848,31 @@ struct sqlite3_module {
 ** ^The estimatedRows value is an estimate of the number of rows that
 ** will be returned by the strategy.
 **
+** The xBestIndex method may optionally populate the idxFlags field with a 
+** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag -
+** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite
+** assumes that the strategy may visit at most one row. 
+**
+** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then
+** SQLite also assumes that if a call to the xUpdate() method is made as
+** part of the same statement to delete or update a virtual table row and the
+** implementation returns SQLITE_CONSTRAINT, then there is no need to rollback
+** any database changes. In other words, if the xUpdate() returns
+** SQLITE_CONSTRAINT, the database contents must be exactly as they were
+** before xUpdate was called. By contrast, if SQLITE_INDEX_SCAN_UNIQUE is not
+** set and xUpdate returns SQLITE_CONSTRAINT, any database changes made by
+** the xUpdate method are automatically rolled back by SQLite.
+**
 ** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
 ** structure for SQLite version 3.8.2. If a virtual table extension is
 ** used with an SQLite version earlier than 3.8.2, the results of attempting 
 ** to read or write the estimatedRows field are undefined (but are likely 
 ** to included crashing the application). The estimatedRows field should
 ** therefore only be used if [sqlite3_libversion_number()] returns a
-** value greater than or equal to 3008002.
+** value greater than or equal to 3008002. Similarly, the idxFlags field
+** was added for version 3.9.0. It may therefore only be used if
+** sqlite3_libversion_number() returns a value greater than or equal to
+** 3009000.
 */
 struct sqlite3_index_info {
   /* Inputs */
@@ -5847,8 +5900,15 @@ struct sqlite3_index_info {
   double estimatedCost;           /* Estimated cost of using this index */
   /* Fields below are only available in SQLite 3.8.2 and later */
   sqlite3_int64 estimatedRows;    /* Estimated number of rows returned */
+  /* Fields below are only available in SQLite 3.9.0 and later */
+  int idxFlags;              /* Mask of SQLITE_INDEX_SCAN_* flags */
 };
 
+/*
+** CAPI3REF: Virtual Table Scan Flags
+*/
+#define SQLITE_INDEX_SCAN_UNIQUE      1     /* Scan visits at most 1 row */
+
 /*
 ** CAPI3REF: Virtual Table Constraint Operator Codes
 **
@@ -6306,6 +6366,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
 ** <li>  SQLITE_MUTEX_STATIC_APP1
 ** <li>  SQLITE_MUTEX_STATIC_APP2
 ** <li>  SQLITE_MUTEX_STATIC_APP3
+** <li>  SQLITE_MUTEX_STATIC_VFS1
+** <li>  SQLITE_MUTEX_STATIC_VFS2
+** <li>  SQLITE_MUTEX_STATIC_VFS3
 ** </ul>
 **
 ** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE)
@@ -8072,6 +8135,527 @@ struct sqlite3_rtree_query_info {
 
 #endif  /* ifndef _SQLITE3RTREE_H_ */
 
+/*
+** 2014 May 31
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** Interfaces to extend FTS5. Using the interfaces defined in this file, 
+** FTS5 may be extended with:
+**
+**     * custom tokenizers, and
+**     * custom auxiliary functions.
+*/
+
+
+#ifndef _FTS5_H
+#define _FTS5_H
+
+/* #include "sqlite3.h" */
+
+#if 0
+extern "C" {
+#endif
+
+/*************************************************************************
+** CUSTOM AUXILIARY FUNCTIONS
+**
+** Virtual table implementations may overload SQL functions by implementing
+** the sqlite3_module.xFindFunction() method.
+*/
+
+typedef struct Fts5ExtensionApi Fts5ExtensionApi;
+typedef struct Fts5Context Fts5Context;
+typedef struct Fts5PhraseIter Fts5PhraseIter;
+
+typedef void (*fts5_extension_function)(
+  const Fts5ExtensionApi *pApi,   /* API offered by current FTS version */
+  Fts5Context *pFts,              /* First arg to pass to pApi functions */
+  sqlite3_context *pCtx,          /* Context for returning result/error */
+  int nVal,                       /* Number of values in apVal[] array */
+  sqlite3_value **apVal           /* Array of trailing arguments */
+);
+
+struct Fts5PhraseIter {
+  const unsigned char *a;
+  const unsigned char *b;
+};
+
+/*
+** EXTENSION API FUNCTIONS
+**
+** xUserData(pFts):
+**   Return a copy of the context pointer the extension function was 
+**   registered with.
+**
+** xColumnTotalSize(pFts, iCol, pnToken):
+**   If parameter iCol is less than zero, set output variable *pnToken
+**   to the total number of tokens in the FTS5 table. Or, if iCol is
+**   non-negative but less than the number of columns in the table, return
+**   the total number of tokens in column iCol, considering all rows in 
+**   the FTS5 table.
+**
+**   If parameter iCol is greater than or equal to the number of columns
+**   in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
+**   an OOM condition or IO error), an appropriate SQLite error code is 
+**   returned.
+**
+** xColumnCount(pFts):
+**   Return the number of columns in the table.
+**
+** xColumnSize(pFts, iCol, pnToken):
+**   If parameter iCol is less than zero, set output variable *pnToken
+**   to the total number of tokens in the current row. Or, if iCol is
+**   non-negative but less than the number of columns in the table, set
+**   *pnToken to the number of tokens in column iCol of the current row.
+**
+**   If parameter iCol is greater than or equal to the number of columns
+**   in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
+**   an OOM condition or IO error), an appropriate SQLite error code is 
+**   returned.
+**
+** xColumnText:
+**   This function attempts to retrieve the text of column iCol of the
+**   current document. If successful, (*pz) is set to point to a buffer
+**   containing the text in utf-8 encoding, (*pn) is set to the size in bytes
+**   (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
+**   if an error occurs, an SQLite error code is returned and the final values
+**   of (*pz) and (*pn) are undefined.
+**
+** xPhraseCount:
+**   Returns the number of phrases in the current query expression.
+**
+** xPhraseSize:
+**   Returns the number of tokens in phrase iPhrase of the query. Phrases
+**   are numbered starting from zero.
+**
+** xInstCount:
+**   Set *pnInst to the total number of occurrences of all phrases within
+**   the query within the current row. Return SQLITE_OK if successful, or
+**   an error code (i.e. SQLITE_NOMEM) if an error occurs.
+**
+** xInst:
+**   Query for the details of phrase match iIdx within the current row.
+**   Phrase matches are numbered starting from zero, so the iIdx argument
+**   should be greater than or equal to zero and smaller than the value
+**   output by xInstCount().
+**
+**   Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) 
+**   if an error occurs.
+**
+** xRowid:
+**   Returns the rowid of the current row.
+**
+** xTokenize:
+**   Tokenize text using the tokenizer belonging to the FTS5 table.
+**
+** xQueryPhrase(pFts5, iPhrase, pUserData, xCallback):
+**   This API function is used to query the FTS table for phrase iPhrase
+**   of the current query. Specifically, a query equivalent to:
+**
+**       ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid
+**
+**   with $p set to a phrase equivalent to the phrase iPhrase of the
+**   current query is executed. For each row visited, the callback function
+**   passed as the fourth argument is invoked. The context and API objects 
+**   passed to the callback function may be used to access the properties of
+**   each matched row. Invoking Api.xUserData() returns a copy of the pointer
+**   passed as the third argument to pUserData.
+**
+**   If the callback function returns any value other than SQLITE_OK, the
+**   query is abandoned and the xQueryPhrase function returns immediately.
+**   If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK.
+**   Otherwise, the error code is propagated upwards.
+**
+**   If the query runs to completion without incident, SQLITE_OK is returned.
+**   Or, if some error occurs before the query completes or is aborted by
+**   the callback, an SQLite error code is returned.
+**
+**
+** xSetAuxdata(pFts5, pAux, xDelete)
+**
+**   Save the pointer passed as the second argument as the extension functions 
+**   "auxiliary data". The pointer may then be retrieved by the current or any
+**   future invocation of the same fts5 extension function made as part of
+**   of the same MATCH query using the xGetAuxdata() API.
+**
+**   Each extension function is allocated a single auxiliary data slot for
+**   each FTS query (MATCH expression). If the extension function is invoked 
+**   more than once for a single FTS query, then all invocations share a 
+**   single auxiliary data context.
+**
+**   If there is already an auxiliary data pointer when this function is
+**   invoked, then it is replaced by the new pointer. If an xDelete callback
+**   was specified along with the original pointer, it is invoked at this
+**   point.
+**
+**   The xDelete callback, if one is specified, is also invoked on the
+**   auxiliary data pointer after the FTS5 query has finished.
+**
+**   If an error (e.g. an OOM condition) occurs within this function, an
+**   the auxiliary data is set to NULL and an error code returned. If the
+**   xDelete parameter was not NULL, it is invoked on the auxiliary data
+**   pointer before returning.
+**
+**
+** xGetAuxdata(pFts5, bClear)
+**
+**   Returns the current auxiliary data pointer for the fts5 extension 
+**   function. See the xSetAuxdata() method for details.
+**
+**   If the bClear argument is non-zero, then the auxiliary data is cleared
+**   (set to NULL) before this function returns. In this case the xDelete,
+**   if any, is not invoked.
+**
+**
+** xRowCount(pFts5, pnRow)
+**
+**   This function is used to retrieve the total number of rows in the table.
+**   In other words, the same value that would be returned by:
+**
+**        SELECT count(*) FROM ftstable;
+**
+** xPhraseFirst()
+**   This function is used, along with type Fts5PhraseIter and the xPhraseNext
+**   method, to iterate through all instances of a single query phrase within
+**   the current row. This is the same information as is accessible via the
+**   xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient
+**   to use, this API may be faster under some circumstances. To iterate 
+**   through instances of phrase iPhrase, use the following code:
+**
+**       Fts5PhraseIter iter;
+**       int iCol, iOff;
+**       for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
+**           iOff>=0;
+**           pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
+**       ){
+**         // An instance of phrase iPhrase at offset iOff of column iCol
+**       }
+**
+**   The Fts5PhraseIter structure is defined above. Applications should not
+**   modify this structure directly - it should only be used as shown above
+**   with the xPhraseFirst() and xPhraseNext() API methods.
+**
+** xPhraseNext()
+**   See xPhraseFirst above.
+*/
+struct Fts5ExtensionApi {
+  int iVersion;                   /* Currently always set to 1 */
+
+  void *(*xUserData)(Fts5Context*);
+
+  int (*xColumnCount)(Fts5Context*);
+  int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
+  int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken);
+
+  int (*xTokenize)(Fts5Context*, 
+    const char *pText, int nText, /* Text to tokenize */
+    void *pCtx,                   /* Context passed to xToken() */
+    int (*xToken)(void*, int, const char*, int, int, int)       /* Callback */
+  );
+
+  int (*xPhraseCount)(Fts5Context*);
+  int (*xPhraseSize)(Fts5Context*, int iPhrase);
+
+  int (*xInstCount)(Fts5Context*, int *pnInst);
+  int (*xInst)(Fts5Context*, int iIdx, int *piPhrase, int *piCol, int *piOff);
+
+  sqlite3_int64 (*xRowid)(Fts5Context*);
+  int (*xColumnText)(Fts5Context*, int iCol, const char **pz, int *pn);
+  int (*xColumnSize)(Fts5Context*, int iCol, int *pnToken);
+
+  int (*xQueryPhrase)(Fts5Context*, int iPhrase, void *pUserData,
+    int(*)(const Fts5ExtensionApi*,Fts5Context*,void*)
+  );
+  int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
+  void *(*xGetAuxdata)(Fts5Context*, int bClear);
+
+  void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
+  void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
+};
+
+/* 
+** CUSTOM AUXILIARY FUNCTIONS
+*************************************************************************/
+
+/*************************************************************************
+** CUSTOM TOKENIZERS
+**
+** Applications may also register custom tokenizer types. A tokenizer 
+** is registered by providing fts5 with a populated instance of the 
+** following structure. All structure methods must be defined, setting
+** any member of the fts5_tokenizer struct to NULL leads to undefined
+** behaviour. The structure methods are expected to function as follows:
+**
+** xCreate:
+**   This function is used to allocate and inititalize a tokenizer instance.
+**   A tokenizer instance is required to actually tokenize text.
+**
+**   The first argument passed to this function is a copy of the (void*)
+**   pointer provided by the application when the fts5_tokenizer object
+**   was registered with FTS5 (the third argument to xCreateTokenizer()). 
+**   The second and third arguments are an array of nul-terminated strings
+**   containing the tokenizer arguments, if any, specified following the
+**   tokenizer name as part of the CREATE VIRTUAL TABLE statement used
+**   to create the FTS5 table.
+**
+**   The final argument is an output variable. If successful, (*ppOut) 
+**   should be set to point to the new tokenizer handle and SQLITE_OK
+**   returned. If an error occurs, some value other than SQLITE_OK should
+**   be returned. In this case, fts5 assumes that the final value of *ppOut 
+**   is undefined.
+**
+** xDelete:
+**   This function is invoked to delete a tokenizer handle previously
+**   allocated using xCreate(). Fts5 guarantees that this function will
+**   be invoked exactly once for each successful call to xCreate().
+**
+** xTokenize:
+**   This function is expected to tokenize the nText byte string indicated 
+**   by argument pText. pText may or may not be nul-terminated. The first
+**   argument passed to this function is a pointer to an Fts5Tokenizer object
+**   returned by an earlier call to xCreate().
+**
+**   The second argument indicates the reason that FTS5 is requesting
+**   tokenization of the supplied text. This is always one of the following
+**   four values:
+**
+**   <ul><li> <b>FTS5_TOKENIZE_DOCUMENT</b> - A document is being inserted into
+**            or removed from the FTS table. The tokenizer is being invoked to
+**            determine the set of tokens to add to (or delete from) the
+**            FTS index.
+**
+**       <li> <b>FTS5_TOKENIZE_QUERY</b> - A MATCH query is being executed 
+**            against the FTS index. The tokenizer is being called to tokenize 
+**            a bareword or quoted string specified as part of the query.
+**
+**       <li> <b>(FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX)</b> - Same as
+**            FTS5_TOKENIZE_QUERY, except that the bareword or quoted string is
+**            followed by a "*" character, indicating that the last token
+**            returned by the tokenizer will be treated as a token prefix.
+**
+**       <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to 
+**            satisfy an fts5_api.xTokenize() request made by an auxiliary
+**            function. Or an fts5_api.xColumnSize() request made by the same
+**            on a columnsize=0 database.  
+**   </ul>
+**
+**   For each token in the input string, the supplied callback xToken() must
+**   be invoked. The first argument to it should be a copy of the pointer
+**   passed as the second argument to xTokenize(). The third and fourth
+**   arguments are a pointer to a buffer containing the token text, and the
+**   size of the token in bytes. The 4th and 5th arguments are the byte offsets
+**   of the first byte of and first byte immediately following the text from
+**   which the token is derived within the input.
+**
+**   The second argument passed to the xToken() callback ("tflags") should
+**   normally be set to 0. The exception is if the tokenizer supports 
+**   synonyms. In this case see the discussion below for details.
+**
+**   FTS5 assumes the xToken() callback is invoked for each token in the 
+**   order that they occur within the input text.
+**
+**   If an xToken() callback returns any value other than SQLITE_OK, then
+**   the tokenization should be abandoned and the xTokenize() method should
+**   immediately return a copy of the xToken() return value. Or, if the
+**   input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally,
+**   if an error occurs with the xTokenize() implementation itself, it
+**   may abandon the tokenization and return any error code other than
+**   SQLITE_OK or SQLITE_DONE.
+**
+** SYNONYM SUPPORT
+**
+**   Custom tokenizers may also support synonyms. Consider a case in which a
+**   user wishes to query for a phrase such as "first place". Using the 
+**   built-in tokenizers, the FTS5 query 'first + place' will match instances
+**   of "first place" within the document set, but not alternative forms
+**   such as "1st place". In some applications, it would be better to match
+**   all instances of "first place" or "1st place" regardless of which form
+**   the user specified in the MATCH query text.
+**
+**   There are several ways to approach this in FTS5:
+**
+**   <ol><li> By mapping all synonyms to a single token. In this case, the 
+**            In the above example, this means that the tokenizer returns the
+**            same token for inputs "first" and "1st". Say that token is in
+**            fact "first", so that when the user inserts the document "I won
+**            1st place" entries are added to the index for tokens "i", "won",
+**            "first" and "place". If the user then queries for '1st + place',
+**            the tokenizer substitutes "first" for "1st" and the query works
+**            as expected.
+**
+**       <li> By adding multiple synonyms for a single term to the FTS index.
+**            In this case, when tokenizing query text, the tokenizer may 
+**            provide multiple synonyms for a single term within the document.
+**            FTS5 then queries the index for each synonym individually. For
+**            example, faced with the query:
+**
+**   <codeblock>
+**     ... MATCH 'first place'</codeblock>
+**
+**            the tokenizer offers both "1st" and "first" as synonyms for the
+**            first token in the MATCH query and FTS5 effectively runs a query 
+**            similar to:
+**
+**   <codeblock>
+**     ... MATCH '(first OR 1st) place'</codeblock>
+**
+**            except that, for the purposes of auxiliary functions, the query
+**            still appears to contain just two phrases - "(first OR 1st)" 
+**            being treated as a single phrase.
+**
+**       <li> By adding multiple synonyms for a single term to the FTS index.
+**            Using this method, when tokenizing document text, the tokenizer
+**            provides multiple synonyms for each token. So that when a 
+**            document such as "I won first place" is tokenized, entries are
+**            added to the FTS index for "i", "won", "first", "1st" and
+**            "place".
+**
+**            This way, even if the tokenizer does not provide synonyms
+**            when tokenizing query text (it should not - to do would be
+**            inefficient), it doesn't matter if the user queries for 
+**            'first + place' or '1st + place', as there are entires in the
+**            FTS index corresponding to both forms of the first token.
+**   </ol>
+**
+**   Whether it is parsing document or query text, any call to xToken that
+**   specifies a <i>tflags</i> argument with the FTS5_TOKEN_COLOCATED bit
+**   is considered to supply a synonym for the previous token. For example,
+**   when parsing the document "I won first place", a tokenizer that supports
+**   synonyms would call xToken() 5 times, as follows:
+**
+**   <codeblock>
+**       xToken(pCtx, 0, "i",                      1,  0,  1);
+**       xToken(pCtx, 0, "won",                    3,  2,  5);
+**       xToken(pCtx, 0, "first",                  5,  6, 11);
+**       xToken(pCtx, FTS5_TOKEN_COLOCATED, "1st", 3,  6, 11);
+**       xToken(pCtx, 0, "place",                  5, 12, 17);
+**</codeblock>
+**
+**   It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time
+**   xToken() is called. Multiple synonyms may be specified for a single token
+**   by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence. 
+**   There is no limit to the number of synonyms that may be provided for a
+**   single token.
+**
+**   In many cases, method (1) above is the best approach. It does not add 
+**   extra data to the FTS index or require FTS5 to query for multiple terms,
+**   so it is efficient in terms of disk space and query speed. However, it
+**   does not support prefix queries very well. If, as suggested above, the
+**   token "first" is subsituted for "1st" by the tokenizer, then the query:
+**
+**   <codeblock>
+**     ... MATCH '1s*'</codeblock>
+**
+**   will not match documents that contain the token "1st" (as the tokenizer
+**   will probably not map "1s" to any prefix of "first").
+**
+**   For full prefix support, method (3) may be preferred. In this case, 
+**   because the index contains entries for both "first" and "1st", prefix
+**   queries such as 'fi*' or '1s*' will match correctly. However, because
+**   extra entries are added to the FTS index, this method uses more space
+**   within the database.
+**
+**   Method (2) offers a midpoint between (1) and (3). Using this method,
+**   a query such as '1s*' will match documents that contain the literal 
+**   token "1st", but not "first" (assuming the tokenizer is not able to
+**   provide synonyms for prefixes). However, a non-prefix query like '1st'
+**   will match against "1st" and "first". This method does not require
+**   extra disk space, as no extra entries are added to the FTS index. 
+**   On the other hand, it may require more CPU cycles to run MATCH queries,
+**   as separate queries of the FTS index are required for each synonym.
+**
+**   When using methods (2) or (3), it is important that the tokenizer only
+**   provide synonyms when tokenizing document text (method (2)) or query
+**   text (method (3)), not both. Doing so will not cause any errors, but is
+**   inefficient.
+*/
+typedef struct Fts5Tokenizer Fts5Tokenizer;
+typedef struct fts5_tokenizer fts5_tokenizer;
+struct fts5_tokenizer {
+  int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
+  void (*xDelete)(Fts5Tokenizer*);
+  int (*xTokenize)(Fts5Tokenizer*, 
+      void *pCtx,
+      int flags,            /* Mask of FTS5_TOKENIZE_* flags */
+      const char *pText, int nText, 
+      int (*xToken)(
+        void *pCtx,         /* Copy of 2nd argument to xTokenize() */
+        int tflags,         /* Mask of FTS5_TOKEN_* flags */
+        const char *pToken, /* Pointer to buffer containing token */
+        int nToken,         /* Size of token in bytes */
+        int iStart,         /* Byte offset of token within input text */
+        int iEnd            /* Byte offset of end of token within input text */
+      )
+  );
+};
+
+/* Flags that may be passed as the third argument to xTokenize() */
+#define FTS5_TOKENIZE_QUERY     0x0001
+#define FTS5_TOKENIZE_PREFIX    0x0002
+#define FTS5_TOKENIZE_DOCUMENT  0x0004
+#define FTS5_TOKENIZE_AUX       0x0008
+
+/* Flags that may be passed by the tokenizer implementation back to FTS5
+** as the third argument to the supplied xToken callback. */
+#define FTS5_TOKEN_COLOCATED    0x0001      /* Same position as prev. token */
+
+/*
+** END OF CUSTOM TOKENIZERS
+*************************************************************************/
+
+/*************************************************************************
+** FTS5 EXTENSION REGISTRATION API
+*/
+typedef struct fts5_api fts5_api;
+struct fts5_api {
+  int iVersion;                   /* Currently always set to 2 */
+
+  /* Create a new tokenizer */
+  int (*xCreateTokenizer)(
+    fts5_api *pApi,
+    const char *zName,
+    void *pContext,
+    fts5_tokenizer *pTokenizer,
+    void (*xDestroy)(void*)
+  );
+
+  /* Find an existing tokenizer */
+  int (*xFindTokenizer)(
+    fts5_api *pApi,
+    const char *zName,
+    void **ppContext,
+    fts5_tokenizer *pTokenizer
+  );
+
+  /* Create a new auxiliary function */
+  int (*xCreateFunction)(
+    fts5_api *pApi,
+    const char *zName,
+    void *pContext,
+    fts5_extension_function xFunction,
+    void (*xDestroy)(void*)
+  );
+};
+
+/*
+** END OF REGISTRATION API
+*************************************************************************/
+
+#if 0
+}  /* end of the 'extern "C"' block */
+#endif
+
+#endif /* _FTS5_H */
+
+
 
 /************** End of sqlite3.h *********************************************/
 /************** Continuing where we left off in sqliteInt.h ******************/
@@ -8363,15 +8947,19 @@ struct sqlite3_rtree_query_info {
 
 /*
 ** Make sure that the compiler intrinsics we desire are enabled when
-** compiling with an appropriate version of MSVC.
-*/
-#if defined(_MSC_VER) && _MSC_VER>=1300
-#  if !defined(_WIN32_WCE)
-#    include <intrin.h>
-#    pragma intrinsic(_byteswap_ushort)
-#    pragma intrinsic(_byteswap_ulong)
-#  else
-#    include <cmnintrin.h>
+** compiling with an appropriate version of MSVC unless prevented by
+** the SQLITE_DISABLE_INTRINSIC define.
+*/
+#if !defined(SQLITE_DISABLE_INTRINSIC)
+#  if defined(_MSC_VER) && _MSC_VER>=1300
+#    if !defined(_WIN32_WCE)
+#      include <intrin.h>
+#      pragma intrinsic(_byteswap_ushort)
+#      pragma intrinsic(_byteswap_ulong)
+#      pragma intrinsic(_ReadWriteBarrier)
+#    else
+#      include <cmnintrin.h>
+#    endif
 #  endif
 #endif
 
@@ -9589,7 +10177,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
 );
 SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor*);
 SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor*, int*);
-SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*);
+SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*, int);
 SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey,
                                   const void *pData, int nData,
                                   int nZero, int bias, int seekResult);
@@ -9983,9 +10571,9 @@ typedef struct VdbeOpList VdbeOpList;
 #define OP_FkCounter     135 /* synopsis: fkctr[P1]+=P2                    */
 #define OP_FkIfZero      136 /* synopsis: if fkctr[P1]==0 goto P2          */
 #define OP_MemMax        137 /* synopsis: r[P1]=max(r[P1],r[P2])           */
-#define OP_IfPos         138 /* synopsis: if r[P1]>0 goto P2               */
-#define OP_IfNeg         139 /* synopsis: r[P1]+=P3, if r[P1]<0 goto P2    */
-#define OP_IfNotZero     140 /* synopsis: if r[P1]!=0 then r[P1]+=P3, goto P2 */
+#define OP_IfPos         138 /* synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
+#define OP_SetIfNotPos   139 /* synopsis: if r[P1]<=0 then r[P2]=P3        */
+#define OP_IfNotZero     140 /* synopsis: if r[P1]!=0 then r[P1]-=P3, goto P2 */
 #define OP_DecrJumpZero  141 /* synopsis: if (--r[P1])==0 goto P2          */
 #define OP_JumpZeroIncr  142 /* synopsis: if (r[P1]++)==0 ) goto P2        */
 #define OP_AggStep0      143 /* synopsis: accum=r[P3] step(r[P2@P5])       */
@@ -10036,7 +10624,7 @@ typedef struct VdbeOpList VdbeOpList;
 /* 112 */ 0x00, 0x10, 0x01, 0x01, 0x01, 0x01, 0x10, 0x00,\
 /* 120 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,\
 /* 128 */ 0x00, 0x06, 0x23, 0x0b, 0x01, 0x10, 0x10, 0x00,\
-/* 136 */ 0x01, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00,\
+/* 136 */ 0x01, 0x04, 0x03, 0x06, 0x03, 0x03, 0x03, 0x00,\
 /* 144 */ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,\
 /* 152 */ 0x00, 0x00, 0x01, 0x00, 0x10, 0x10, 0x01, 0x00,\
 /* 160 */ 0x00,}
@@ -10052,12 +10640,16 @@ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse*);
 SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe*,int);
 SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe*,int,int);
 SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe*,int,int,int);
+SQLITE_PRIVATE int sqlite3VdbeGoto(Vdbe*,int);
+SQLITE_PRIVATE int sqlite3VdbeLoadString(Vdbe*,int,const char*);
+SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe*,int,const char*,...);
 SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int);
 SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int);
 SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8(Vdbe*,int,int,int,int,const u8*,int);
 SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int);
 SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno);
 SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
+SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8);
 SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1);
 SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2);
 SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3);
@@ -10301,6 +10893,9 @@ SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
 /* Functions used to configure a Pager object. */
 SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
 SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int);
+#ifdef SQLITE_HAS_CODEC
+SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager*,Pager*);
+#endif
 SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager*, int);
 SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
 SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
@@ -11335,18 +11930,20 @@ struct FuncDestructor {
 ** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG.  There
 ** are assert() statements in the code to verify this.
 */
-#define SQLITE_FUNC_ENCMASK  0x003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */
-#define SQLITE_FUNC_LIKE     0x004 /* Candidate for the LIKE optimization */
-#define SQLITE_FUNC_CASE     0x008 /* Case-sensitive LIKE-type function */
-#define SQLITE_FUNC_EPHEM    0x010 /* Ephemeral.  Delete with VDBE */
-#define SQLITE_FUNC_NEEDCOLL 0x020 /* sqlite3GetFuncCollSeq() might be called */
-#define SQLITE_FUNC_LENGTH   0x040 /* Built-in length() function */
-#define SQLITE_FUNC_TYPEOF   0x080 /* Built-in typeof() function */
-#define SQLITE_FUNC_COUNT    0x100 /* Built-in count(*) aggregate */
-#define SQLITE_FUNC_COALESCE 0x200 /* Built-in coalesce() or ifnull() */
-#define SQLITE_FUNC_UNLIKELY 0x400 /* Built-in unlikely() function */
-#define SQLITE_FUNC_CONSTANT 0x800 /* Constant inputs give a constant output */
-#define SQLITE_FUNC_MINMAX  0x1000 /* True for min() and max() aggregates */
+#define SQLITE_FUNC_ENCMASK  0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */
+#define SQLITE_FUNC_LIKE     0x0004 /* Candidate for the LIKE optimization */
+#define SQLITE_FUNC_CASE     0x0008 /* Case-sensitive LIKE-type function */
+#define SQLITE_FUNC_EPHEM    0x0010 /* Ephemeral.  Delete with VDBE */
+#define SQLITE_FUNC_NEEDCOLL 0x0020 /* sqlite3GetFuncCollSeq() might be called*/
+#define SQLITE_FUNC_LENGTH   0x0040 /* Built-in length() function */
+#define SQLITE_FUNC_TYPEOF   0x0080 /* Built-in typeof() function */
+#define SQLITE_FUNC_COUNT    0x0100 /* Built-in count(*) aggregate */
+#define SQLITE_FUNC_COALESCE 0x0200 /* Built-in coalesce() or ifnull() */
+#define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */
+#define SQLITE_FUNC_CONSTANT 0x0800 /* Constant inputs give a constant output */
+#define SQLITE_FUNC_MINMAX   0x1000 /* True for min() and max() aggregates */
+#define SQLITE_FUNC_SLOCHNG  0x2000 /* "Slow Change". Value constant during a
+                                    ** single query - might change over time */
 
 /*
 ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
@@ -11362,6 +11959,12 @@ struct FuncDestructor {
 **   VFUNCTION(zName, nArg, iArg, bNC, xFunc)
 **     Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag.
 **
+**   DFUNCTION(zName, nArg, iArg, bNC, xFunc)
+**     Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and
+**     adds the SQLITE_FUNC_SLOCHNG flag.  Used for date & time functions
+**     and functions like sqlite_version() that can change, but not during
+**     a single query.
+**
 **   AGGREGATE(zName, nArg, iArg, bNC, xStep, xFinal)
 **     Used to create an aggregate function definition implemented by
 **     the C functions xStep and xFinal. The first four parameters
@@ -11382,11 +11985,14 @@ struct FuncDestructor {
 #define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \
   {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
    SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
+#define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \
+  {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
+   SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 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, 0, #zName, 0, 0}
 #define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
-  {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
+  {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
    pArg, 0, xFunc, 0, 0, #zName, 0, 0}
 #define LIKEFUNC(zName, nArg, arg, flags) \
   {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \
@@ -11430,6 +12036,7 @@ struct Module {
   const char *zName;                   /* Name passed to create_module() */
   void *pAux;                          /* pAux passed to create_module() */
   void (*xDestroy)(void *);            /* Module destructor function */
+  Table *pEpoTab;                      /* Eponymous table for this module */
 };
 
 /*
@@ -11475,6 +12082,7 @@ struct CollSeq {
 */
 #define SQLITE_SO_ASC       0  /* Sort in ascending order */
 #define SQLITE_SO_DESC      1  /* Sort in ascending order */
+#define SQLITE_SO_UNDEFINED -1 /* No sort order specified */
 
 /*
 ** Column affinity types.
@@ -11581,9 +12189,8 @@ struct Table {
   Select *pSelect;     /* NULL for tables.  Points to definition if a view. */
   FKey *pFKey;         /* Linked list of all foreign keys in this table */
   char *zColAff;       /* String defining the affinity of each column */
-#ifndef SQLITE_OMIT_CHECK
   ExprList *pCheck;    /* All CHECK constraints */
-#endif
+                       /*   ... also used as column name list in a VIEW */
   int tnum;            /* Root BTree page for this table */
   i16 iPKey;           /* If not negative, use aCol[iPKey] as the rowid */
   i16 nCol;            /* Number of columns in this table */
@@ -11600,7 +12207,7 @@ struct Table {
 #endif
 #ifndef SQLITE_OMIT_VIRTUALTABLE
   int nModuleArg;      /* Number of arguments to the module */
-  char **azModuleArg;  /* Text of all module args. [0] is module name */
+  char **azModuleArg;  /* 0: module 1: schema 2: vtab name 3...: args */
   VTable *pVTable;     /* List of VTable objects. */
 #endif
   Trigger *pTrigger;   /* List of triggers stored in pSchema */
@@ -11821,6 +12428,7 @@ struct Index {
   u8 *aSortOrder;          /* for each column: True==DESC, False==ASC */
   char **azColl;           /* Array of collation sequence names for index */
   Expr *pPartIdxWhere;     /* WHERE clause for partial indices */
+  ExprList *aColExpr;      /* Column expressions */
   int tnum;                /* DB Page containing root of this index */
   LogEst szIdxRow;         /* Estimated average row size in bytes */
   u16 nKeyCol;             /* Number of columns forming the key */
@@ -11855,6 +12463,12 @@ struct Index {
 /* Return true if index X is a UNIQUE index */
 #define IsUniqueIndex(X)      ((X)->onError!=OE_None)
 
+/* The Index.aiColumn[] values are normally positive integer.  But
+** there are some negative values that have special meaning:
+*/
+#define XN_ROWID     (-1)     /* Indexed column is the rowid */
+#define XN_EXPR      (-2)     /* Indexed column is an expression */
+
 /*
 ** Each sample stored in the sqlite_stat3 table is represented in memory 
 ** using a structure of this type.  See documentation at the top of the
@@ -12070,9 +12684,10 @@ struct Expr {
 #define EP_MemToken  0x010000 /* Need to sqlite3DbFree() Expr.zToken */
 #define EP_NoReduce  0x020000 /* Cannot EXPRDUP_REDUCE this Expr */
 #define EP_Unlikely  0x040000 /* unlikely() or likelihood() function */
-#define EP_ConstFunc 0x080000 /* Node is a SQLITE_FUNC_CONSTANT function */
+#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
 #define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
 #define EP_Subquery  0x200000 /* Tree contains a TK_SELECT operator */
+#define EP_Alias     0x400000 /* Is an alias for a result set column */
 
 /*
 ** Combinations of two or more EP_* flags
@@ -12235,11 +12850,15 @@ struct SrcList {
     int addrFillSub;  /* Address of subroutine to manifest a subquery */
     int regReturn;    /* Register holding return address of addrFillSub */
     int regResult;    /* Registers holding results of a co-routine */
-    u8 jointype;      /* Type of join between this able and the previous */
-    unsigned notIndexed :1;    /* True if there is a NOT INDEXED clause */
-    unsigned isCorrelated :1;  /* True if sub-query is correlated */
-    unsigned viaCoroutine :1;  /* Implemented as a co-routine */
-    unsigned isRecursive :1;   /* True for recursive reference in WITH */
+    struct {
+      u8 jointype;      /* Type of join between this able and the previous */
+      unsigned notIndexed :1;    /* True if there is a NOT INDEXED clause */
+      unsigned isIndexedBy :1;   /* True if there is an INDEXED BY clause */
+      unsigned isTabFunc :1;     /* True if table-valued-function syntax */
+      unsigned isCorrelated :1;  /* True if sub-query is correlated */
+      unsigned viaCoroutine :1;  /* Implemented as a co-routine */
+      unsigned isRecursive :1;   /* True for recursive reference in WITH */
+    } fg;
 #ifndef SQLITE_OMIT_EXPLAIN
     u8 iSelectId;     /* If pSelect!=0, the id of the sub-select in EQP */
 #endif
@@ -12247,8 +12866,11 @@ struct SrcList {
     Expr *pOn;        /* The ON clause of a join */
     IdList *pUsing;   /* The USING clause of a join */
     Bitmask colUsed;  /* Bit N (1<<N) set if column N of pTab is used */
-    char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
-    Index *pIndex;    /* Index structure corresponding to zIndex, if any */
+    union {
+      char *zIndexedBy;    /* Identifier from "INDEXED BY <zIndex>" clause */
+      ExprList *pFuncArg;  /* Arguments to table-valued-function */
+    } u1;
+    Index *pIBIndex;  /* Index structure corresponding to u1.zIndexedBy */
   } a[1];             /* One entry for each identifier on the list */
 };
 
@@ -12282,6 +12904,7 @@ struct SrcList {
 #define WHERE_WANT_DISTINCT    0x0400 /* All output needs to be distinct */
 #define WHERE_SORTBYGROUP      0x0800 /* Support sqlite3WhereIsSorted() */
 #define WHERE_REOPEN_IDX       0x1000 /* Try to use OP_ReopenIdx */
+#define WHERE_ONEPASS_MULTIROW 0x2000 /* ONEPASS is ok with multiple rows */
 
 /* Allowed return values from sqlite3WhereIsDistinct()
 */
@@ -12334,6 +12957,7 @@ struct NameContext {
 #define NC_IsCheck   0x0004  /* True if resolving names in a CHECK constraint */
 #define NC_InAggFunc 0x0008  /* True if analyzing arguments to an agg func */
 #define NC_PartIdx   0x0010  /* True if resolving a partial index WHERE */
+#define NC_IdxExpr   0x0020  /* True if resolving columns of CREATE INDEX */
 #define NC_MinMaxAgg 0x1000  /* min/max aggregates seen.  See note above */
 
 /*
@@ -12603,7 +13227,7 @@ struct Parse {
   int nOpAlloc;        /* Number of slots allocated for Vdbe.aOp[] */
   int iFixedOp;        /* Never back out opcodes iFixedOp-1 or earlier */
   int ckBase;          /* Base register of data during check constraints */
-  int iPartIdxTab;     /* Table corresponding to a partial index */
+  int iSelfTab;        /* Table of an index whose exprs are being coded */
   int iCacheLevel;     /* ColCache valid when aColCache[].iLevel<=iCacheLevel */
   int iCacheCnt;       /* Counter used to generate aColCache[].lru values */
   int nLabel;          /* Number of labels used */
@@ -12973,7 +13597,7 @@ struct With {
     char *zName;                    /* Name of this CTE */
     ExprList *pCols;                /* List of explicit column names, or NULL */
     Select *pSelect;                /* The definition of this CTE */
-    const char *zErr;               /* Error message for circular references */
+    const char *zCteErr;            /* Error message for circular references */
   } a[1];
 };
 
@@ -13121,6 +13745,11 @@ SQLITE_PRIVATE   sqlite3_mutex *sqlite3MutexAlloc(int);
 SQLITE_PRIVATE   int sqlite3MutexInit(void);
 SQLITE_PRIVATE   int sqlite3MutexEnd(void);
 #endif
+#if !defined(SQLITE_MUTEX_OMIT) && !defined(SQLITE_MUTEX_NOOP)
+SQLITE_PRIVATE   void sqlite3MemoryBarrier(void);
+#else
+# define sqlite3MemoryBarrier()
+#endif
 
 SQLITE_PRIVATE sqlite3_int64 sqlite3StatusValue(int);
 SQLITE_PRIVATE void sqlite3StatusUp(int, int);
@@ -13187,6 +13816,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*);
 SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*);
 SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*);
 SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
+SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int);
 SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int);
 SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*);
 SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3*, ExprList*);
@@ -13199,6 +13829,8 @@ SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3*,int);
 SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3*);
 SQLITE_PRIVATE void sqlite3BeginParse(Parse*,int);
 SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3*);
+SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3*,Table*);
+SQLITE_PRIVATE int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**);
 SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*);
 SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *, int);
 SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table*);
@@ -13240,7 +13872,7 @@ SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet*, i64);
 SQLITE_PRIVATE int sqlite3RowSetTest(RowSet*, int iBatch, i64);
 SQLITE_PRIVATE int sqlite3RowSetNext(RowSet*, i64*);
 
-SQLITE_PRIVATE void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);
+SQLITE_PRIVATE void sqlite3CreateView(Parse*,Token*,Token*,Token*,ExprList*,Select*,int,int);
 
 #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
 SQLITE_PRIVATE   int sqlite3ViewGetColumnNames(Parse*,Table*);
@@ -13270,6 +13902,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(sqlite3*, SrcList*, Token*, Token*)
 SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*,
                                       Token*, Select*, Expr*, IdList*);
 SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *);
+SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*);
 SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *, struct SrcList_item *);
 SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(SrcList*);
 SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse*, SrcList*);
@@ -13300,6 +13933,10 @@ SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo*);
 SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo*);
 SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo*);
 SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo*, int*);
+#define ONEPASS_OFF      0        /* Use of ONEPASS not allowed */
+#define ONEPASS_SINGLE   1        /* ONEPASS valid for a single row update */
+#define ONEPASS_MULTI    2        /* ONEPASS is valid for multiple rows */
+SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int);
 SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
 SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
 SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int);
@@ -13315,9 +13952,10 @@ SQLITE_PRIVATE void sqlite3ExprCodeAtInit(Parse*, Expr*, int, u8);
 SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
 SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse*, Expr*, int);
 SQLITE_PRIVATE void sqlite3ExprCodeAndCache(Parse*, Expr*, int);
-SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, u8);
+SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8);
 #define SQLITE_ECEL_DUP      0x01  /* Deep, not shallow copies */
 #define SQLITE_ECEL_FACTOR   0x02  /* Factor out constant terms */
+#define SQLITE_ECEL_REF      0x04  /* Use ExprList.u.x.iOrderByCol */
 SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
 SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
 SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int);
@@ -13358,8 +13996,9 @@ SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr*, int*);
 SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*);
 SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
 SQLITE_PRIVATE int sqlite3IsRowid(const char*);
-SQLITE_PRIVATE void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8);
-SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*);
+SQLITE_PRIVATE void sqlite3GenerateRowDelete(
+    Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int);
+SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int);
 SQLITE_PRIVATE int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int);
 SQLITE_PRIVATE void sqlite3ResolvePartIdxLabel(Parse*,int);
 SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int,
@@ -13417,6 +14056,7 @@ SQLITE_PRIVATE   void sqlite3DeleteTrigger(sqlite3*, Trigger*);
 SQLITE_PRIVATE   void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
 SQLITE_PRIVATE   u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Table*,int);
 # define sqlite3ParseToplevel(p) ((p)->pToplevel ? (p)->pToplevel : (p))
+# define sqlite3IsToplevel(p) ((p)->pToplevel==0)
 #else
 # define sqlite3TriggersExist(B,C,D,E,F) 0
 # define sqlite3DeleteTrigger(A,B)
@@ -13426,6 +14066,7 @@ SQLITE_PRIVATE   u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Tab
 # define sqlite3CodeRowTriggerDirect(A,B,C,D,E,F)
 # define sqlite3TriggerList(X, Y) 0
 # define sqlite3ParseToplevel(p) p
+# define sqlite3IsToplevel(p) 1
 # define sqlite3TriggerColmask(A,B,C,D,E,F,G) 0
 #endif
 
@@ -13489,7 +14130,7 @@ SQLITE_PRIVATE int sqlite3VarintLen(u64 v);
 #define putVarint    sqlite3PutVarint
 
 
-SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(Vdbe *, Index *);
+SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3*, Index*);
 SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe*, Table*, int);
 SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2);
 SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
@@ -13561,6 +14202,7 @@ SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*);
 SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p);
 SQLITE_PRIVATE int sqlite3MatchSpanName(const char*, const char*, const char*, const char*);
 SQLITE_PRIVATE int sqlite3ResolveExprNames(NameContext*, Expr*);
+SQLITE_PRIVATE int sqlite3ResolveExprListNames(NameContext*, ExprList*);
 SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
 SQLITE_PRIVATE void sqlite3ResolveSelfReference(Parse*,Table*,int,Expr*,ExprList*);
 SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
@@ -13669,6 +14311,8 @@ SQLITE_PRIVATE    void sqlite3VtabImportErrmsg(Vdbe*, sqlite3_vtab*);
 SQLITE_PRIVATE    VTable *sqlite3GetVTable(sqlite3*, Table*);
 #  define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
 #endif
+SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse*,Module*);
+SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3*,Module*);
 SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse*,Table*);
 SQLITE_PRIVATE void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*, int);
 SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse*, Token*);
@@ -14242,12 +14886,18 @@ static const char * const azCompileOpt[] = {
 #if SQLITE_ENABLE_FTS4
   "ENABLE_FTS4",
 #endif
+#if SQLITE_ENABLE_FTS5
+  "ENABLE_FTS5",
+#endif
 #if SQLITE_ENABLE_ICU
   "ENABLE_ICU",
 #endif
 #if SQLITE_ENABLE_IOTRACE
   "ENABLE_IOTRACE",
 #endif
+#if SQLITE_ENABLE_JSON1
+  "ENABLE_JSON1",
+#endif
 #if SQLITE_ENABLE_LOAD_EXTENSION
   "ENABLE_LOAD_EXTENSION",
 #endif
@@ -14772,6 +15422,7 @@ struct Mem {
   } u;
   u16 flags;          /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
   u8  enc;            /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
+  u8  eSubtype;       /* Subtype for this value */
   int n;              /* Number of characters in string value, excluding '\0' */
   char *z;            /* String or BLOB value */
   /* ShallowCopy only needs to copy the information above */
@@ -16548,14 +17199,14 @@ static void currentTimeFunc(
 SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
   static SQLITE_WSD FuncDef aDateTimeFuncs[] = {
 #ifndef SQLITE_OMIT_DATETIME_FUNCS
-    FUNCTION(julianday,        -1, 0, 0, juliandayFunc ),
-    FUNCTION(date,             -1, 0, 0, dateFunc      ),
-    FUNCTION(time,             -1, 0, 0, timeFunc      ),
-    FUNCTION(datetime,         -1, 0, 0, datetimeFunc  ),
-    FUNCTION(strftime,         -1, 0, 0, strftimeFunc  ),
-    FUNCTION(current_time,      0, 0, 0, ctimeFunc     ),
-    FUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc),
-    FUNCTION(current_date,      0, 0, 0, cdateFunc     ),
+    DFUNCTION(julianday,        -1, 0, 0, juliandayFunc ),
+    DFUNCTION(date,             -1, 0, 0, dateFunc      ),
+    DFUNCTION(time,             -1, 0, 0, timeFunc      ),
+    DFUNCTION(datetime,         -1, 0, 0, datetimeFunc  ),
+    DFUNCTION(strftime,         -1, 0, 0, strftimeFunc  ),
+    DFUNCTION(current_time,      0, 0, 0, ctimeFunc     ),
+    DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc),
+    DFUNCTION(current_date,      0, 0, 0, cdateFunc     ),
 #else
     STR_FUNCTION(current_time,      0, "%H:%M:%S",          0, currentTimeFunc),
     STR_FUNCTION(current_date,      0, "%Y-%m-%d",          0, currentTimeFunc),
@@ -19244,7 +19895,7 @@ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void){
 ** allocate a mutex while the system is uninitialized.
 */
 static SQLITE_WSD int mutexIsInit = 0;
-#endif /* SQLITE_DEBUG */
+#endif /* SQLITE_DEBUG && !defined(SQLITE_MUTEX_OMIT) */
 
 
 #ifndef SQLITE_MUTEX_OMIT
@@ -19275,8 +19926,10 @@ SQLITE_PRIVATE int sqlite3MutexInit(void){
     pTo->xMutexLeave = pFrom->xMutexLeave;
     pTo->xMutexHeld = pFrom->xMutexHeld;
     pTo->xMutexNotheld = pFrom->xMutexNotheld;
+    sqlite3MemoryBarrier();
     pTo->xMutexAlloc = pFrom->xMutexAlloc;
   }
+  assert( sqlite3GlobalConfig.mutex.xMutexInit );
   rc = sqlite3GlobalConfig.mutex.xMutexInit();
 
 #ifdef SQLITE_DEBUG
@@ -19311,6 +19964,7 @@ SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_mutex_alloc(int id){
   if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0;
   if( id>SQLITE_MUTEX_RECURSIVE && sqlite3MutexInit() ) return 0;
 #endif
+  assert( sqlite3GlobalConfig.mutex.xMutexAlloc );
   return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
 }
 
@@ -19319,6 +19973,7 @@ SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int id){
     return 0;
   }
   assert( GLOBAL(int, mutexIsInit) );
+  assert( sqlite3GlobalConfig.mutex.xMutexAlloc );
   return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
 }
 
@@ -19327,6 +19982,7 @@ SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int id){
 */
 SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex *p){
   if( p ){
+    assert( sqlite3GlobalConfig.mutex.xMutexFree );
     sqlite3GlobalConfig.mutex.xMutexFree(p);
   }
 }
@@ -19337,6 +19993,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex *p){
 */
 SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex *p){
   if( p ){
+    assert( sqlite3GlobalConfig.mutex.xMutexEnter );
     sqlite3GlobalConfig.mutex.xMutexEnter(p);
   }
 }
@@ -19348,6 +20005,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex *p){
 SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex *p){
   int rc = SQLITE_OK;
   if( p ){
+    assert( sqlite3GlobalConfig.mutex.xMutexTry );
     return sqlite3GlobalConfig.mutex.xMutexTry(p);
   }
   return rc;
@@ -19361,6 +20019,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex *p){
 */
 SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex *p){
   if( p ){
+    assert( sqlite3GlobalConfig.mutex.xMutexLeave );
     sqlite3GlobalConfig.mutex.xMutexLeave(p);
   }
 }
@@ -19371,9 +20030,11 @@ SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex *p){
 ** intended for use inside assert() statements.
 */
 SQLITE_API int SQLITE_STDCALL sqlite3_mutex_held(sqlite3_mutex *p){
+  assert( p==0 || sqlite3GlobalConfig.mutex.xMutexHeld );
   return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p);
 }
 SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex *p){
+  assert( p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld );
   return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p);
 }
 #endif
@@ -19682,6 +20343,19 @@ static int pthreadMutexNotheld(sqlite3_mutex *p){
 }
 #endif
 
+/*
+** Try to provide a memory barrier operation, needed for initialization
+** and also for the implementation of xShmBarrier in the VFS in cases
+** where SQLite is compiled without mutexes.
+*/
+SQLITE_PRIVATE void sqlite3MemoryBarrier(void){
+#if defined(SQLITE_MEMORY_BARRIER)
+  SQLITE_MEMORY_BARRIER;
+#elif defined(__GNUC__) && GCC_VERSION>=4001000
+  __sync_synchronize();
+#endif
+}
+
 /*
 ** Initialize and deinitialize the mutex subsystem.
 */
@@ -20344,6 +21018,24 @@ static int winMutexNotheld(sqlite3_mutex *p){
 }
 #endif
 
+/*
+** Try to provide a memory barrier operation, needed for initialization
+** and also for the xShmBarrier method of the VFS in cases when SQLite is
+** compiled without mutexes (SQLITE_THREADSAFE=0).
+*/
+SQLITE_PRIVATE void sqlite3MemoryBarrier(void){
+#if defined(SQLITE_MEMORY_BARRIER)
+  SQLITE_MEMORY_BARRIER;
+#elif defined(__GNUC__)
+  __sync_synchronize();
+#elif !defined(SQLITE_DISABLE_INTRINSIC) && \
+      defined(_MSC_VER) && _MSC_VER>=1300
+  _ReadWriteBarrier();
+#elif defined(MemoryBarrier)
+  MemoryBarrier();
+#endif
+}
+
 /*
 ** Initialize and deinitialize the mutex subsystem.
 */
@@ -20697,16 +21389,7 @@ typedef struct ScratchFreeslot {
 */
 static SQLITE_WSD struct Mem0Global {
   sqlite3_mutex *mutex;         /* Mutex to serialize access */
-
-  /*
-  ** The alarm callback and its arguments.  The mem0.mutex lock will
-  ** be held while the callback is running.  Recursive calls into
-  ** the memory subsystem are allowed, but no new callbacks will be
-  ** issued.
-  */
-  sqlite3_int64 alarmThreshold;
-  void (*alarmCallback)(void*, sqlite3_int64,int);
-  void *alarmArg;
+  sqlite3_int64 alarmThreshold; /* The soft heap limit */
 
   /*
   ** Pointers to the end of sqlite3GlobalConfig.pScratch memory
@@ -20723,7 +21406,7 @@ static SQLITE_WSD struct Mem0Global {
   ** sqlite3_soft_heap_limit() setting.
   */
   int nearlyFull;
-} mem0 = { 0, 0, 0, 0, 0, 0, 0, 0 };
+} mem0 = { 0, 0, 0, 0, 0, 0 };
 
 #define mem0 GLOBAL(struct Mem0Global, mem0)
 
@@ -20734,50 +21417,21 @@ SQLITE_PRIVATE sqlite3_mutex *sqlite3MallocMutex(void){
   return mem0.mutex;
 }
 
-/*
-** This routine runs when the memory allocator sees that the
-** total memory allocation is about to exceed the soft heap
-** limit.
-*/
-static void softHeapLimitEnforcer(
-  void *NotUsed, 
-  sqlite3_int64 NotUsed2,
-  int allocSize
-){
-  UNUSED_PARAMETER2(NotUsed, NotUsed2);
-  sqlite3_release_memory(allocSize);
-}
-
-/*
-** Change the alarm callback
-*/
-static int sqlite3MemoryAlarm(
-  void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
-  void *pArg,
-  sqlite3_int64 iThreshold
-){
-  sqlite3_int64 nUsed;
-  sqlite3_mutex_enter(mem0.mutex);
-  mem0.alarmCallback = xCallback;
-  mem0.alarmArg = pArg;
-  mem0.alarmThreshold = iThreshold;
-  nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
-  mem0.nearlyFull = (iThreshold>0 && iThreshold<=nUsed);
-  sqlite3_mutex_leave(mem0.mutex);
-  return SQLITE_OK;
-}
-
 #ifndef SQLITE_OMIT_DEPRECATED
 /*
-** Deprecated external interface.  Internal/core SQLite code
-** should call sqlite3MemoryAlarm.
+** Deprecated external interface.  It used to set an alarm callback
+** that was invoked when memory usage grew too large.  Now it is a
+** no-op.
 */
 SQLITE_API int SQLITE_STDCALL sqlite3_memory_alarm(
   void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
   void *pArg,
   sqlite3_int64 iThreshold
 ){
-  return sqlite3MemoryAlarm(xCallback, pArg, iThreshold);
+  (void)xCallback;
+  (void)pArg;
+  (void)iThreshold;
+  return SQLITE_OK;
 }
 #endif
 
@@ -20788,19 +21442,21 @@ SQLITE_API int SQLITE_STDCALL sqlite3_memory_alarm(
 SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 n){
   sqlite3_int64 priorLimit;
   sqlite3_int64 excess;
+  sqlite3_int64 nUsed;
 #ifndef SQLITE_OMIT_AUTOINIT
   int rc = sqlite3_initialize();
   if( rc ) return -1;
 #endif
   sqlite3_mutex_enter(mem0.mutex);
   priorLimit = mem0.alarmThreshold;
-  sqlite3_mutex_leave(mem0.mutex);
-  if( n<0 ) return priorLimit;
-  if( n>0 ){
-    sqlite3MemoryAlarm(softHeapLimitEnforcer, 0, n);
-  }else{
-    sqlite3MemoryAlarm(0, 0, 0);
+  if( n<0 ){
+    sqlite3_mutex_leave(mem0.mutex);
+    return priorLimit;
   }
+  mem0.alarmThreshold = n;
+  nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
+  mem0.nearlyFull = (n>0 && n<=nUsed);
+  sqlite3_mutex_leave(mem0.mutex);
   excess = sqlite3_memory_used() - n;
   if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff));
   return priorLimit;
@@ -20897,19 +21553,10 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag){
 ** Trigger the alarm 
 */
 static void sqlite3MallocAlarm(int nByte){
-  void (*xCallback)(void*,sqlite3_int64,int);
-  sqlite3_int64 nowUsed;
-  void *pArg;
-  if( mem0.alarmCallback==0 ) return;
-  xCallback = mem0.alarmCallback;
-  nowUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
-  pArg = mem0.alarmArg;
-  mem0.alarmCallback = 0;
+  if( mem0.alarmThreshold<=0 ) return;
   sqlite3_mutex_leave(mem0.mutex);
-  xCallback(pArg, nowUsed, nByte);
+  sqlite3_release_memory(nByte);
   sqlite3_mutex_enter(mem0.mutex);
-  mem0.alarmCallback = xCallback;
-  mem0.alarmArg = pArg;
 }
 
 /*
@@ -20922,7 +21569,7 @@ static int mallocWithAlarm(int n, void **pp){
   assert( sqlite3_mutex_held(mem0.mutex) );
   nFull = sqlite3GlobalConfig.m.xRoundup(n);
   sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, n);
-  if( mem0.alarmCallback!=0 ){
+  if( mem0.alarmThreshold>0 ){
     sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
     if( nUsed >= mem0.alarmThreshold - nFull ){
       mem0.nearlyFull = 1;
@@ -20933,7 +21580,7 @@ static int mallocWithAlarm(int n, void **pp){
   }
   p = sqlite3GlobalConfig.m.xMalloc(nFull);
 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
-  if( p==0 && mem0.alarmCallback ){
+  if( p==0 && mem0.alarmThreshold>0 ){
     sqlite3MallocAlarm(nFull);
     p = sqlite3GlobalConfig.m.xMalloc(nFull);
   }
@@ -21108,19 +21755,20 @@ SQLITE_PRIVATE int sqlite3MallocSize(void *p){
   return sqlite3GlobalConfig.m.xSize(p);
 }
 SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
-  if( db==0 ){
-    assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
-    assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
-    return sqlite3MallocSize(p);
-  }else{
-    assert( sqlite3_mutex_held(db->mutex) );
-    if( isLookaside(db, p) ){
-      return db->lookaside.sz;
+  if( db==0 || !isLookaside(db,p) ){
+#if SQLITE_DEBUG
+    if( db==0 ){
+      assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
+      assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
     }else{
       assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
       assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
-      return sqlite3GlobalConfig.m.xSize(p);
     }
+#endif
+    return sqlite3GlobalConfig.m.xSize(p);
+  }else{
+    assert( sqlite3_mutex_held(db->mutex) );
+    return db->lookaside.sz;
   }
 }
 SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void *p){
@@ -21221,7 +21869,7 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){
       sqlite3MallocAlarm(nDiff);
     }
     pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
-    if( pNew==0 && mem0.alarmCallback ){
+    if( pNew==0 && mem0.alarmThreshold>0 ){
       sqlite3MallocAlarm((int)nBytes);
       pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
     }
@@ -21935,21 +22583,16 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
         if( realvalue>0.0 ){
           LONGDOUBLE_TYPE scale = 1.0;
           while( realvalue>=1e100*scale && exp<=350 ){ scale *= 1e100;exp+=100;}
-          while( realvalue>=1e64*scale && exp<=350 ){ scale *= 1e64; exp+=64; }
-          while( realvalue>=1e8*scale && exp<=350 ){ scale *= 1e8; exp+=8; }
+          while( realvalue>=1e10*scale && exp<=350 ){ scale *= 1e10; exp+=10; }
           while( realvalue>=10.0*scale && exp<=350 ){ scale *= 10.0; exp++; }
           realvalue /= scale;
           while( realvalue<1e-8 ){ realvalue *= 1e8; exp-=8; }
           while( realvalue<1.0 ){ realvalue *= 10.0; exp--; }
           if( exp>350 ){
-            if( prefix=='-' ){
-              bufpt = "-Inf";
-            }else if( prefix=='+' ){
-              bufpt = "+Inf";
-            }else{
-              bufpt = "Inf";
-            }
-            length = sqlite3Strlen30(bufpt);
+            bufpt = buf;
+            buf[0] = prefix;
+            memcpy(buf+(prefix!=0),"Inf",4);
+            length = 3+(prefix!=0);
             break;
           }
         }
@@ -22098,12 +22741,13 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
       case etDYNSTRING:
         if( bArgList ){
           bufpt = getTextArg(pArgList);
+          xtype = etSTRING;
         }else{
           bufpt = va_arg(ap,char*);
         }
         if( bufpt==0 ){
           bufpt = "";
-        }else if( xtype==etDYNSTRING && !bArgList ){
+        }else if( xtype==etDYNSTRING ){
           zExtra = bufpt;
         }
         if( precision>=0 ){
@@ -22112,9 +22756,9 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
           length = sqlite3Strlen30(bufpt);
         }
         break;
-      case etSQLESCAPE:
-      case etSQLESCAPE2:
-      case etSQLESCAPE3: {
+      case etSQLESCAPE:           /* Escape ' characters */
+      case etSQLESCAPE2:          /* Escape ' and enclose in '...' */
+      case etSQLESCAPE3: {        /* Escape " characters */
         int i, j, k, n, isnull;
         int needQuote;
         char ch;
@@ -22133,7 +22777,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
           if( ch==q )  n++;
         }
         needQuote = !isnull && xtype==etSQLESCAPE2;
-        n += i + 1 + needQuote*2;
+        n += i + 3;
         if( n>etBUFSIZE ){
           bufpt = zExtra = sqlite3Malloc( n );
           if( bufpt==0 ){
@@ -22529,7 +23173,8 @@ SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){
 
 
 /*
-** variable-argument wrapper around sqlite3VXPrintf().
+** variable-argument wrapper around sqlite3VXPrintf().  The bFlags argument
+** can contain the bit SQLITE_PRINTF_INTERNAL enable internal formats.
 */
 SQLITE_PRIVATE void sqlite3XPrintf(StrAccum *p, u32 bFlags, const char *zFormat, ...){
   va_list ap;
@@ -22627,90 +23272,100 @@ static void sqlite3TreeViewItem(TreeView *p, const char *zLabel,u8 moreFollows){
 */
 SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
   int n = 0;
+  int cnt = 0;
   pView = sqlite3TreeViewPush(pView, moreToFollow);
-  sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x",
-    ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
-    ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags
-  );
-  if( p->pSrc && p->pSrc->nSrc ) n++;
-  if( p->pWhere ) n++;
-  if( p->pGroupBy ) n++;
-  if( p->pHaving ) n++;
-  if( p->pOrderBy ) n++;
-  if( p->pLimit ) n++;
-  if( p->pOffset ) n++;
-  if( p->pPrior ) n++;
-  sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set");
-  if( p->pSrc && p->pSrc->nSrc ){
-    int i;
-    pView = sqlite3TreeViewPush(pView, (n--)>0);
-    sqlite3TreeViewLine(pView, "FROM");
-    for(i=0; i<p->pSrc->nSrc; i++){
-      struct SrcList_item *pItem = &p->pSrc->a[i];
-      StrAccum x;
-      char zLine[100];
-      sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
-      sqlite3XPrintf(&x, 0, "{%d,*}", pItem->iCursor);
-      if( pItem->zDatabase ){
-        sqlite3XPrintf(&x, 0, " %s.%s", pItem->zDatabase, pItem->zName);
-      }else if( pItem->zName ){
-        sqlite3XPrintf(&x, 0, " %s", pItem->zName);
-      }
-      if( pItem->pTab ){
-        sqlite3XPrintf(&x, 0, " tabname=%Q", pItem->pTab->zName);
-      }
-      if( pItem->zAlias ){
-        sqlite3XPrintf(&x, 0, " (AS %s)", pItem->zAlias);
-      }
-      if( pItem->jointype & JT_LEFT ){
-        sqlite3XPrintf(&x, 0, " LEFT-JOIN");
-      }
-      sqlite3StrAccumFinish(&x);
-      sqlite3TreeViewItem(pView, zLine, i<p->pSrc->nSrc-1); 
-      if( pItem->pSelect ){
-        sqlite3TreeViewSelect(pView, pItem->pSelect, 0);
+  do{
+    sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x",
+      ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
+      ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags
+    );
+    if( cnt++ ) sqlite3TreeViewPop(pView);
+    if( p->pPrior ){
+      n = 1000;
+    }else{
+      n = 0;
+      if( p->pSrc && p->pSrc->nSrc ) n++;
+      if( p->pWhere ) n++;
+      if( p->pGroupBy ) n++;
+      if( p->pHaving ) n++;
+      if( p->pOrderBy ) n++;
+      if( p->pLimit ) n++;
+      if( p->pOffset ) n++;
+    }
+    sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set");
+    if( p->pSrc && p->pSrc->nSrc ){
+      int i;
+      pView = sqlite3TreeViewPush(pView, (n--)>0);
+      sqlite3TreeViewLine(pView, "FROM");
+      for(i=0; i<p->pSrc->nSrc; i++){
+        struct SrcList_item *pItem = &p->pSrc->a[i];
+        StrAccum x;
+        char zLine[100];
+        sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
+        sqlite3XPrintf(&x, 0, "{%d,*}", pItem->iCursor);
+        if( pItem->zDatabase ){
+          sqlite3XPrintf(&x, 0, " %s.%s", pItem->zDatabase, pItem->zName);
+        }else if( pItem->zName ){
+          sqlite3XPrintf(&x, 0, " %s", pItem->zName);
+        }
+        if( pItem->pTab ){
+          sqlite3XPrintf(&x, 0, " tabname=%Q", pItem->pTab->zName);
+        }
+        if( pItem->zAlias ){
+          sqlite3XPrintf(&x, 0, " (AS %s)", pItem->zAlias);
+        }
+        if( pItem->fg.jointype & JT_LEFT ){
+          sqlite3XPrintf(&x, 0, " LEFT-JOIN");
+        }
+        sqlite3StrAccumFinish(&x);
+        sqlite3TreeViewItem(pView, zLine, i<p->pSrc->nSrc-1); 
+        if( pItem->pSelect ){
+          sqlite3TreeViewSelect(pView, pItem->pSelect, 0);
+        }
+        if( pItem->fg.isTabFunc ){
+          sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:");
+        }
+        sqlite3TreeViewPop(pView);
       }
       sqlite3TreeViewPop(pView);
     }
-    sqlite3TreeViewPop(pView);
-  }
-  if( p->pWhere ){
-    sqlite3TreeViewItem(pView, "WHERE", (n--)>0);
-    sqlite3TreeViewExpr(pView, p->pWhere, 0);
-    sqlite3TreeViewPop(pView);
-  }
-  if( p->pGroupBy ){
-    sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY");
-  }
-  if( p->pHaving ){
-    sqlite3TreeViewItem(pView, "HAVING", (n--)>0);
-    sqlite3TreeViewExpr(pView, p->pHaving, 0);
-    sqlite3TreeViewPop(pView);
-  }
-  if( p->pOrderBy ){
-    sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY");
-  }
-  if( p->pLimit ){
-    sqlite3TreeViewItem(pView, "LIMIT", (n--)>0);
-    sqlite3TreeViewExpr(pView, p->pLimit, 0);
-    sqlite3TreeViewPop(pView);
-  }
-  if( p->pOffset ){
-    sqlite3TreeViewItem(pView, "OFFSET", (n--)>0);
-    sqlite3TreeViewExpr(pView, p->pOffset, 0);
-    sqlite3TreeViewPop(pView);
-  }
-  if( p->pPrior ){
-    const char *zOp = "UNION";
-    switch( p->op ){
-      case TK_ALL:         zOp = "UNION ALL";  break;
-      case TK_INTERSECT:   zOp = "INTERSECT";  break;
-      case TK_EXCEPT:      zOp = "EXCEPT";     break;
-    }
-    sqlite3TreeViewItem(pView, zOp, (n--)>0);
-    sqlite3TreeViewSelect(pView, p->pPrior, 0);
-    sqlite3TreeViewPop(pView);
-  }
+    if( p->pWhere ){
+      sqlite3TreeViewItem(pView, "WHERE", (n--)>0);
+      sqlite3TreeViewExpr(pView, p->pWhere, 0);
+      sqlite3TreeViewPop(pView);
+    }
+    if( p->pGroupBy ){
+      sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY");
+    }
+    if( p->pHaving ){
+      sqlite3TreeViewItem(pView, "HAVING", (n--)>0);
+      sqlite3TreeViewExpr(pView, p->pHaving, 0);
+      sqlite3TreeViewPop(pView);
+    }
+    if( p->pOrderBy ){
+      sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY");
+    }
+    if( p->pLimit ){
+      sqlite3TreeViewItem(pView, "LIMIT", (n--)>0);
+      sqlite3TreeViewExpr(pView, p->pLimit, 0);
+      sqlite3TreeViewPop(pView);
+    }
+    if( p->pOffset ){
+      sqlite3TreeViewItem(pView, "OFFSET", (n--)>0);
+      sqlite3TreeViewExpr(pView, p->pOffset, 0);
+      sqlite3TreeViewPop(pView);
+    }
+    if( p->pPrior ){
+      const char *zOp = "UNION";
+      switch( p->op ){
+        case TK_ALL:         zOp = "UNION ALL";  break;
+        case TK_INTERSECT:   zOp = "INTERSECT";  break;
+        case TK_EXCEPT:      zOp = "EXCEPT";     break;
+      }
+      sqlite3TreeViewItem(pView, zOp, 1);
+    }
+    p = p->pPrior;
+  }while( p!=0 );
   sqlite3TreeViewPop(pView);
 }
 
@@ -22785,11 +23440,6 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
       sqlite3TreeViewLine(pView,"REGISTER(%d)", pExpr->iTable);
       break;
     }
-    case TK_AS: {
-      sqlite3TreeViewLine(pView,"AS %Q", pExpr->u.zToken);
-      sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
-      break;
-    }
     case TK_ID: {
       sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken);
       break;
@@ -22964,7 +23614,13 @@ SQLITE_PRIVATE void sqlite3TreeViewExprList(
   }else{
     sqlite3TreeViewLine(pView, "%s", zLabel);
     for(i=0; i<pList->nExpr; i++){
+      int j = pList->a[i].u.x.iOrderByCol;
+      if( j ){
+        sqlite3TreeViewPush(pView, 0);
+        sqlite3TreeViewLine(pView, "iOrderByCol=%d", j);
+      }
       sqlite3TreeViewExpr(pView, pList->a[i].pExpr, i<pList->nExpr-1);
+      if( j ) sqlite3TreeViewPop(pView);
     }
   }
   sqlite3TreeViewPop(pView);
@@ -23180,6 +23836,10 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(
   memset(p, 0, sizeof(*p));
   p->xTask = xTask;
   p->pIn = pIn;
+  /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a 
+  ** function that returns SQLITE_ERROR when passed the argument 200, that
+  ** forces worker threads to run sequentially and deterministically 
+  ** for testing purposes. */
   if( sqlite3FaultSim(200) ){
     rc = 1;
   }else{    
@@ -23264,7 +23924,12 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(
   *ppThread = 0;
   p = sqlite3Malloc(sizeof(*p));
   if( p==0 ) return SQLITE_NOMEM;
-  if( sqlite3GlobalConfig.bCoreMutex==0 ){
+  /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a 
+  ** function that returns SQLITE_ERROR when passed the argument 200, that
+  ** forces worker threads to run sequentially and deterministically 
+  ** (via the sqlite3FaultSim() term of the conditional) for testing
+  ** purposes. */
+  if( sqlite3GlobalConfig.bCoreMutex==0 || sqlite3FaultSim(200) ){
     memset(p, 0, sizeof(*p));
   }else{
     p->xTask = xTask;
@@ -23292,7 +23957,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
   assert( ppOut!=0 );
   if( NEVER(p==0) ) return SQLITE_NOMEM;
   if( p->xTask==0 ){
-    assert( p->id==GetCurrentThreadId() );
+    /* assert( p->id==GetCurrentThreadId() ); */
     rc = WAIT_OBJECT_0;
     assert( p->tid==0 );
   }else{
@@ -24979,11 +25644,8 @@ SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){
 ** 64-bit integer.
 */
 SQLITE_PRIVATE int sqlite3VarintLen(u64 v){
-  int i = 0;
-  do{
-    i++;
-    v >>= 7;
-  }while( v!=0 && ALWAYS(i<9) );
+  int i;
+  for(i=1; (v >>= 7)!=0; i++){ assert( i<9 ); }
   return i;
 }
 
@@ -24996,11 +25658,13 @@ SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){
   u32 x;
   memcpy(&x,p,4);
   return x;
-#elif SQLITE_BYTEORDER==1234 && defined(__GNUC__) && GCC_VERSION>=4003000
+#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
+    && defined(__GNUC__) && GCC_VERSION>=4003000
   u32 x;
   memcpy(&x,p,4);
   return __builtin_bswap32(x);
-#elif SQLITE_BYTEORDER==1234 && defined(_MSC_VER) && _MSC_VER>=1300
+#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
+    && defined(_MSC_VER) && _MSC_VER>=1300
   u32 x;
   memcpy(&x,p,4);
   return _byteswap_ulong(x);
@@ -25729,9 +26393,9 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
      /* 135 */ "FkCounter"        OpHelp("fkctr[P1]+=P2"),
      /* 136 */ "FkIfZero"         OpHelp("if fkctr[P1]==0 goto P2"),
      /* 137 */ "MemMax"           OpHelp("r[P1]=max(r[P1],r[P2])"),
-     /* 138 */ "IfPos"            OpHelp("if r[P1]>0 goto P2"),
-     /* 139 */ "IfNeg"            OpHelp("r[P1]+=P3, if r[P1]<0 goto P2"),
-     /* 140 */ "IfNotZero"        OpHelp("if r[P1]!=0 then r[P1]+=P3, goto P2"),
+     /* 138 */ "IfPos"            OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
+     /* 139 */ "SetIfNotPos"      OpHelp("if r[P1]<=0 then r[P2]=P3"),
+     /* 140 */ "IfNotZero"        OpHelp("if r[P1]!=0 then r[P1]-=P3, goto P2"),
      /* 141 */ "DecrJumpZero"     OpHelp("if (--r[P1])==0 goto P2"),
      /* 142 */ "JumpZeroIncr"     OpHelp("if (r[P1]++)==0 ) goto P2"),
      /* 143 */ "AggStep0"         OpHelp("accum=r[P3] step(r[P2@P5])"),
@@ -29105,7 +29769,6 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
   TIMER_START;
   assert( cnt==(cnt&0x1ffff) );
   assert( id->h>2 );
-  cnt &= 0x1ffff;
   do{
 #if defined(USE_PREAD)
     got = osPread(id->h, pBuf, cnt, offset);
@@ -29322,8 +29985,8 @@ static int unixWrite(
     }
   }
 #endif
-
-  while( amt>0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt))>0 ){
+  while( (wrote = seekAndWrite(pFile, offset, pBuf, amt))<amt && wrote>0 ){
     amt -= wrote;
     offset += wrote;
     pBuf = &((char*)pBuf)[wrote];
@@ -29331,7 +29994,7 @@ static int unixWrite(
   SimulateIOError(( wrote=(-1), amt=1 ));
   SimulateDiskfullError(( wrote=0, amt=1 ));
 
-  if( amt>0 ){
+  if( amt>wrote ){
     if( wrote<0 && pFile->lastErrno!=ENOSPC ){
       /* lastErrno set by seekAndWrite */
       return SQLITE_IOERR_WRITE;
@@ -30620,7 +31283,8 @@ static void unixShmBarrier(
   sqlite3_file *fd                /* Database file holding the shared memory */
 ){
   UNUSED_PARAMETER(fd);
-  unixEnterMutex();
+  sqlite3MemoryBarrier();         /* compiler-defined memory barrier */
+  unixEnterMutex();               /* Also mutex, for redundancy */
   unixLeaveMutex();
 }
 
@@ -37575,8 +38239,8 @@ static void winShmBarrier(
   sqlite3_file *fd          /* Database holding the shared memory */
 ){
   UNUSED_PARAMETER(fd);
-  /* MemoryBarrier(); // does not work -- do not know why not */
-  winShmEnterMutex();
+  sqlite3MemoryBarrier();   /* compiler-defined memory barrier */
+  winShmEnterMutex();       /* Also mutex, for redundancy */
   winShmLeaveMutex();
 }
 
@@ -39800,7 +40464,7 @@ bitvec_end:
 struct PCache {
   PgHdr *pDirty, *pDirtyTail;         /* List of dirty pages in LRU order */
   PgHdr *pSynced;                     /* Last synced page in dirty page list */
-  int nRef;                           /* Number of referenced pages */
+  int nRefSum;                        /* Sum of ref counts over all pages */
   int szCache;                        /* Configured cache size */
   int szPage;                         /* Size of every page in this cache */
   int szExtra;                        /* Size of extra space for each page */
@@ -39965,7 +40629,7 @@ SQLITE_PRIVATE int sqlite3PcacheOpen(
 ** are no outstanding page references when this function is called.
 */
 SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
-  assert( pCache->nRef==0 && pCache->pDirty==0 );
+  assert( pCache->nRefSum==0 && pCache->pDirty==0 );
   if( pCache->szPage ){
     sqlite3_pcache *pNew;
     pNew = sqlite3GlobalConfig.pcache2.xCreate(
@@ -40132,9 +40796,7 @@ SQLITE_PRIVATE PgHdr *sqlite3PcacheFetchFinish(
   if( !pPgHdr->pPage ){
     return pcacheFetchFinishWithInit(pCache, pgno, pPage);
   }
-  if( 0==pPgHdr->nRef ){
-    pCache->nRef++;
-  }
+  pCache->nRefSum++;
   pPgHdr->nRef++;
   return pPgHdr;
 }
@@ -40145,9 +40807,8 @@ SQLITE_PRIVATE PgHdr *sqlite3PcacheFetchFinish(
 */
 SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
   assert( p->nRef>0 );
-  p->nRef--;
-  if( p->nRef==0 ){
-    p->pCache->nRef--;
+  p->pCache->nRefSum--;
+  if( (--p->nRef)==0 ){
     if( p->flags&PGHDR_CLEAN ){
       pcacheUnpin(p);
     }else if( p->pDirtyPrev!=0 ){
@@ -40163,6 +40824,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
 SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr *p){
   assert(p->nRef>0);
   p->nRef++;
+  p->pCache->nRefSum++;
 }
 
 /*
@@ -40175,7 +40837,7 @@ SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){
   if( p->flags&PGHDR_DIRTY ){
     pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
   }
-  p->pCache->nRef--;
+  p->pCache->nRefSum--;
   sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 1);
 }
 
@@ -40271,11 +40933,11 @@ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
         sqlite3PcacheMakeClean(p);
       }
     }
-    if( pgno==0 && pCache->nRef ){
+    if( pgno==0 && pCache->nRefSum ){
       sqlite3_pcache_page *pPage1;
       pPage1 = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache,1,0);
       if( ALWAYS(pPage1) ){  /* Page 1 is always available in cache, because
-                             ** pCache->nRef>0 */
+                             ** pCache->nRefSum>0 */
         memset(pPage1->pBuf, 0, pCache->szPage);
         pgno = 1;
       }
@@ -40381,10 +41043,13 @@ SQLITE_PRIVATE PgHdr *sqlite3PcacheDirtyList(PCache *pCache){
 }
 
 /* 
-** Return the total number of referenced pages held by the cache.
+** Return the total number of references to all pages held by the cache.
+**
+** This is not the total number of pages referenced, but the sum of the
+** reference count for all pages.
 */
 SQLITE_PRIVATE int sqlite3PcacheRefCount(PCache *pCache){
-  return pCache->nRef;
+  return pCache->nRefSum;
 }
 
 /*
@@ -40519,7 +41184,7 @@ SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHd
 ** that is allocated when the page cache is created.  The size of the local
 ** bulk allocation can be adjusted using 
 **
-**     sqlite3_config(SQLITE_CONFIG_PCACHE, 0, 0, N).
+**     sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, N).
 **
 ** If N is positive, then N pages worth of memory are allocated using a single
 ** sqlite3Malloc() call and that memory is used for the first N pages allocated.
@@ -40541,6 +41206,24 @@ typedef struct PgHdr1 PgHdr1;
 typedef struct PgFreeslot PgFreeslot;
 typedef struct PGroup PGroup;
 
+/*
+** Each cache entry is represented by an instance of the following 
+** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of
+** PgHdr1.pCache->szPage bytes is allocated directly before this structure 
+** in memory.
+*/
+struct PgHdr1 {
+  sqlite3_pcache_page page;      /* Base class. Must be first. pBuf & pExtra */
+  unsigned int iKey;             /* Key value (page number) */
+  u8 isPinned;                   /* Page in use, not on the LRU list */
+  u8 isBulkLocal;                /* This page from bulk local storage */
+  u8 isAnchor;                   /* This is the PGroup.lru element */
+  PgHdr1 *pNext;                 /* Next in hash table chain */
+  PCache1 *pCache;               /* Cache that currently owns this page */
+  PgHdr1 *pLruNext;              /* Next in LRU list of unpinned pages */
+  PgHdr1 *pLruPrev;              /* Previous in LRU list of unpinned pages */
+};
+
 /* Each page cache (or PCache) belongs to a PGroup.  A PGroup is a set 
 ** of one or more PCaches that are able to recycle each other's unpinned
 ** pages when they are under memory pressure.  A PGroup is an instance of
@@ -40569,7 +41252,7 @@ struct PGroup {
   unsigned int nMinPage;         /* Sum of nMin for purgeable caches */
   unsigned int mxPinned;         /* nMaxpage + 10 - nMinPage */
   unsigned int nCurrentPage;     /* Number of purgeable pages allocated */
-  PgHdr1 *pLruHead, *pLruTail;   /* LRU list of unpinned pages */
+  PgHdr1 lru;                    /* The beginning and end of the LRU list */
 };
 
 /* Each page cache is an instance of the following object.  Every
@@ -40607,23 +41290,6 @@ struct PCache1 {
   void *pBulk;                        /* Bulk memory used by pcache-local */
 };
 
-/*
-** Each cache entry is represented by an instance of the following 
-** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of
-** PgHdr1.pCache->szPage bytes is allocated directly before this structure 
-** in memory.
-*/
-struct PgHdr1 {
-  sqlite3_pcache_page page;
-  unsigned int iKey;             /* Key value (page number) */
-  u8 isPinned;                   /* Page in use, not on the LRU list */
-  u8 isBulkLocal;                /* This page from bulk local storage */
-  PgHdr1 *pNext;                 /* Next in hash table chain */
-  PCache1 *pCache;               /* Cache that currently owns this page */
-  PgHdr1 *pLruNext;              /* Next in LRU list of unpinned pages */
-  PgHdr1 *pLruPrev;              /* Previous in LRU list of unpinned pages */
-};
-
 /*
 ** Free slots in the allocator used to divide up the global page cache
 ** buffer provided using the SQLITE_CONFIG_PAGECACHE mechanism.
@@ -40684,6 +41350,7 @@ static SQLITE_WSD struct PCacheGlobal {
 /******************************************************************************/
 /******** Page Allocation/SQLITE_CONFIG_PCACHE Related Functions **************/
 
+
 /*
 ** This function is called during initialization if a static buffer is 
 ** supplied to use for the page-cache by passing the SQLITE_CONFIG_PAGECACHE
@@ -40743,6 +41410,7 @@ static int pcache1InitBulk(PCache1 *pCache){
       pX->page.pBuf = zBulk;
       pX->page.pExtra = &pX[1];
       pX->isBulkLocal = 1;
+      pX->isAnchor = 0;
       pX->pNext = pCache->pFree;
       pCache->pFree = pX;
       zBulk += pCache->szAlloc;
@@ -40846,7 +41514,7 @@ static int pcache1MemSize(void *p){
 /*
 ** Allocate a new page object initially associated with cache pCache.
 */
-static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
+static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
   PgHdr1 *p = 0;
   void *pPg;
 
@@ -40864,6 +41532,7 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
     assert( pCache->pGroup==&pcache1.grp );
     pcache1LeaveMutex(pCache->pGroup);
 #endif
+    if( benignMalloc ){ sqlite3BeginBenignMalloc(); }
 #ifdef SQLITE_PCACHE_SEPARATE_HEADER
     pPg = pcache1Alloc(pCache->szPage);
     p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra);
@@ -40876,6 +41545,7 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
     pPg = pcache1Alloc(pCache->szAlloc);
     p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
 #endif
+    if( benignMalloc ){ sqlite3EndBenignMalloc(); }
 #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
     pcache1EnterMutex(pCache->pGroup);
 #endif
@@ -40883,6 +41553,7 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
     p->page.pBuf = pPg;
     p->page.pExtra = &p[1];
     p->isBulkLocal = 0;
+    p->isAnchor = 0;
   }
   if( pCache->bPurgeable ){
     pCache->pGroup->nCurrentPage++;
@@ -41009,22 +41680,16 @@ static PgHdr1 *pcache1PinPage(PgHdr1 *pPage){
   assert( pPage!=0 );
   assert( pPage->isPinned==0 );
   pCache = pPage->pCache;
-  assert( pPage->pLruNext || pPage==pCache->pGroup->pLruTail );
-  assert( pPage->pLruPrev || pPage==pCache->pGroup->pLruHead );
+  assert( pPage->pLruNext );
+  assert( pPage->pLruPrev );
   assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
-  if( pPage->pLruPrev ){
-    pPage->pLruPrev->pLruNext = pPage->pLruNext;
-  }else{
-    pCache->pGroup->pLruHead = pPage->pLruNext;
-  }
-  if( pPage->pLruNext ){
-    pPage->pLruNext->pLruPrev = pPage->pLruPrev;
-  }else{
-    pCache->pGroup->pLruTail = pPage->pLruPrev;
-  }
+  pPage->pLruPrev->pLruNext = pPage->pLruNext;
+  pPage->pLruNext->pLruPrev = pPage->pLruPrev;
   pPage->pLruNext = 0;
   pPage->pLruPrev = 0;
   pPage->isPinned = 1;
+  assert( pPage->isAnchor==0 );
+  assert( pCache->pGroup->lru.isAnchor==1 );
   pCache->nRecyclable--;
   return pPage;
 }
@@ -41057,9 +41722,11 @@ static void pcache1RemoveFromHash(PgHdr1 *pPage, int freeFlag){
 */
 static void pcache1EnforceMaxPage(PCache1 *pCache){
   PGroup *pGroup = pCache->pGroup;
+  PgHdr1 *p;
   assert( sqlite3_mutex_held(pGroup->mutex) );
-  while( pGroup->nCurrentPage>pGroup->nMaxPage && pGroup->pLruTail ){
-    PgHdr1 *p = pGroup->pLruTail;
+  while( pGroup->nCurrentPage>pGroup->nMaxPage
+      && (p=pGroup->lru.pLruPrev)->isAnchor==0
+  ){
     assert( p->pCache->pGroup==pGroup );
     assert( p->isPinned==0 );
     pcache1PinPage(p);
@@ -41193,6 +41860,10 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
     }else{
       pGroup = &pcache1.grp;
     }
+    if( pGroup->lru.isAnchor==0 ){
+      pGroup->lru.isAnchor = 1;
+      pGroup->lru.pLruPrev = pGroup->lru.pLruNext = &pGroup->lru;
+    }
     pCache->pGroup = pGroup;
     pCache->szPage = szPage;
     pCache->szExtra = szExtra;
@@ -41300,11 +41971,11 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
 
   /* Step 4. Try to recycle a page. */
   if( pCache->bPurgeable
-   && pGroup->pLruTail
+   && !pGroup->lru.pLruPrev->isAnchor
    && ((pCache->nPage+1>=pCache->nMax) || pcache1UnderMemoryPressure(pCache))
   ){
     PCache1 *pOther;
-    pPage = pGroup->pLruTail;
+    pPage = pGroup->lru.pLruPrev;
     assert( pPage->isPinned==0 );
     pcache1RemoveFromHash(pPage, 0);
     pcache1PinPage(pPage);
@@ -41321,9 +41992,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
   ** attempt to allocate a new one. 
   */
   if( !pPage ){
-    if( createFlag==1 ){ sqlite3BeginBenignMalloc(); }
-    pPage = pcache1AllocPage(pCache);
-    if( createFlag==1 ){ sqlite3EndBenignMalloc(); }
+    pPage = pcache1AllocPage(pCache, createFlag==1);
   }
 
   if( pPage ){
@@ -41415,7 +42084,10 @@ static PgHdr1 *pcache1FetchNoMutex(
   pPage = pCache->apHash[iKey % pCache->nHash];
   while( pPage && pPage->iKey!=iKey ){ pPage = pPage->pNext; }
 
-  /* Step 2: Abort if no existing page is found and createFlag is 0 */
+  /* Step 2: If the page was found in the hash table, then return it.
+  ** If the page was not in the hash table and createFlag is 0, abort.
+  ** Otherwise (page not in hash and createFlag!=0) continue with
+  ** subsequent steps to try to create the page. */
   if( pPage ){
     if( !pPage->isPinned ){
       return pcache1PinPage(pPage);
@@ -41492,21 +42164,16 @@ static void pcache1Unpin(
   ** part of the PGroup LRU list.
   */
   assert( pPage->pLruPrev==0 && pPage->pLruNext==0 );
-  assert( pGroup->pLruHead!=pPage && pGroup->pLruTail!=pPage );
   assert( pPage->isPinned==1 );
 
   if( reuseUnlikely || pGroup->nCurrentPage>pGroup->nMaxPage ){
     pcache1RemoveFromHash(pPage, 1);
   }else{
     /* Add the page to the PGroup LRU list. */
-    if( pGroup->pLruHead ){
-      pGroup->pLruHead->pLruPrev = pPage;
-      pPage->pLruNext = pGroup->pLruHead;
-      pGroup->pLruHead = pPage;
-    }else{
-      pGroup->pLruTail = pPage;
-      pGroup->pLruHead = pPage;
-    }
+    PgHdr1 **ppFirst = &pGroup->lru.pLruNext;
+    pPage->pLruPrev = &pGroup->lru;
+    (pPage->pLruNext = *ppFirst)->pLruPrev = pPage;
+    *ppFirst = pPage;
     pCache->nRecyclable++;
     pPage->isPinned = 0;
   }
@@ -41644,7 +42311,10 @@ SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
   if( sqlite3GlobalConfig.nPage==0 ){
     PgHdr1 *p;
     pcache1EnterMutex(&pcache1.grp);
-    while( (nReq<0 || nFree<nReq) && ((p=pcache1.grp.pLruTail)!=0) ){
+    while( (nReq<0 || nFree<nReq)
+       &&  (p=pcache1.grp.lru.pLruPrev)!=0
+       &&  p->isAnchor==0
+    ){
       nFree += pcache1MemSize(p->page.pBuf);
 #ifdef SQLITE_PCACHE_SEPARATE_HEADER
       nFree += sqlite3MemSize(p);
@@ -41672,7 +42342,7 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
 ){
   PgHdr1 *p;
   int nRecyclable = 0;
-  for(p=pcache1.grp.pLruHead; p; p=p->pLruNext){
+  for(p=pcache1.grp.lru.pLruNext; p && !p->isAnchor; p=p->pLruNext){
     assert( p->isPinned==0 );
     nRecyclable++;
   }
@@ -42986,7 +43656,7 @@ struct Pager {
   u8 doNotSpill;              /* Do not spill the cache when non-zero */
   u8 subjInMemory;            /* True to use in-memory sub-journals */
   u8 bUseFetch;               /* True to use xFetch() */
-  u8 hasBeenUsed;             /* True if any content previously read */
+  u8 hasHeldSharedLock;       /* True if a shared lock has ever been held */
   Pgno dbSize;                /* Number of pages in the database */
   Pgno dbOrigSize;            /* dbSize before the current transaction */
   Pgno dbFileSize;            /* Number of pages in the database file */
@@ -44455,6 +45125,20 @@ static void pagerReportSize(Pager *pPager){
 # define pagerReportSize(X)     /* No-op if we do not support a codec */
 #endif
 
+#ifdef SQLITE_HAS_CODEC
+/*
+** Make sure the number of reserved bits is the same in the destination
+** pager as it is in the source.  This comes up when a VACUUM changes the
+** number of reserved bits to the "optimal" amount.
+*/
+SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager *pDest, Pager *pSrc){
+  if( pDest->nReserve!=pSrc->nReserve ){
+    pDest->nReserve = pSrc->nReserve;
+    pagerReportSize(pDest);
+  }
+}
+#endif
+
 /*
 ** Read a single page from either the journal file (if isMainJrnl==1) or
 ** from the sub-journal (if isMainJrnl==0) and playback that page.
@@ -47436,10 +48120,10 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
       );
     }
 
-    if( !pPager->tempFile && pPager->hasBeenUsed ){
+    if( !pPager->tempFile && pPager->hasHeldSharedLock ){
       /* The shared-lock has just been acquired then check to
       ** see if the database has been modified.  If the database has changed,
-      ** flush the cache.  The pPager->hasBeenUsed flag prevents this from
+      ** flush the cache.  The hasHeldSharedLock flag prevents this from
       ** occurring on the very first access to a file, in order to save a
       ** single unnecessary sqlite3OsRead() call at the start-up.
       **
@@ -47509,6 +48193,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
     assert( pPager->eState==PAGER_OPEN );
   }else{
     pPager->eState = PAGER_READER;
+    pPager->hasHeldSharedLock = 1;
   }
   return rc;
 }
@@ -47592,21 +48277,25 @@ SQLITE_PRIVATE int sqlite3PagerAcquire(
   ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY
   ** flag was specified by the caller. And so long as the db is not a 
   ** temporary or in-memory database.  */
-  const int bMmapOk = (pgno!=1 && USEFETCH(pPager)
+  const int bMmapOk = (pgno>1 && USEFETCH(pPager)
    && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY))
 #ifdef SQLITE_HAS_CODEC
    && pPager->xCodec==0
 #endif
   );
 
+  /* Optimization note:  Adding the "pgno<=1" term before "pgno==0" here
+  ** allows the compiler optimizer to reuse the results of the "pgno>1"
+  ** test in the previous statement, and avoid testing pgno==0 in the
+  ** common case where pgno is large. */
+  if( pgno<=1 && pgno==0 ){
+    return SQLITE_CORRUPT_BKPT;
+  }
   assert( pPager->eState>=PAGER_READER );
   assert( assert_pager_state(pPager) );
   assert( noContent==0 || bMmapOk==0 );
 
-  if( pgno==0 ){
-    return SQLITE_CORRUPT_BKPT;
-  }
-  pPager->hasBeenUsed = 1;
+  assert( pPager->hasHeldSharedLock==1 );
 
   /* If the pager is in the error state, return an error immediately. 
   ** Otherwise, request the page from the PCache layer. */
@@ -47761,7 +48450,7 @@ SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
   assert( pgno!=0 );
   assert( pPager->pPCache!=0 );
   pPage = sqlite3PcacheFetch(pPager->pPCache, pgno, 0);
-  assert( pPage==0 || pPager->hasBeenUsed );
+  assert( pPage==0 || pPager->hasHeldSharedLock );
   if( pPage==0 ) return 0;
   return sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pPage);
 }
@@ -48728,7 +49417,7 @@ SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager *pPager){
 
 #ifdef SQLITE_DEBUG
 /*
-** Return the number of references to the pager.
+** Return the sum of the reference counts for all pages held by pPager.
 */
 SQLITE_PRIVATE int sqlite3PagerRefcount(Pager *pPager){
   return sqlite3PcacheRefCount(pPager->pPCache);
@@ -50040,6 +50729,7 @@ struct Wal {
   u8 syncHeader;             /* Fsync the WAL header if true */
   u8 padToSectorBoundary;    /* Pad transactions out to the next sector */
   WalIndexHdr hdr;           /* Wal-index header for current transaction */
+  u32 minFrame;              /* Ignore wal frames before this one */
   const char *zWalName;      /* Name of WAL file */
   u32 nCkpt;                 /* Checkpoint sequence counter in the wal-header */
 #ifdef SQLITE_DEBUG
@@ -51908,12 +52598,27 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
     ** pWal->hdr.mxFrame risks reading a corrupted snapshot. So, retry
     ** instead.
     **
-    ** This does not guarantee that the copy of the wal-index header is up to
-    ** date before proceeding. That would not be possible without somehow
-    ** blocking writers. It only guarantees that a dangerous checkpoint or 
-    ** log-wrap (either of which would require an exclusive lock on
-    ** WAL_READ_LOCK(mxI)) has not occurred since the snapshot was valid.
+    ** Before checking that the live wal-index header has not changed
+    ** since it was read, set Wal.minFrame to the first frame in the wal
+    ** file that has not yet been checkpointed. This client will not need
+    ** to read any frames earlier than minFrame from the wal file - they
+    ** can be safely read directly from the database file.
+    **
+    ** Because a ShmBarrier() call is made between taking the copy of 
+    ** nBackfill and checking that the wal-header in shared-memory still
+    ** matches the one cached in pWal->hdr, it is guaranteed that the 
+    ** checkpointer that set nBackfill was not working with a wal-index
+    ** header newer than that cached in pWal->hdr. If it were, that could
+    ** cause a problem. The checkpointer could omit to checkpoint
+    ** a version of page X that lies before pWal->minFrame (call that version
+    ** A) on the basis that there is a newer version (version B) of the same
+    ** page later in the wal file. But if version B happens to like past
+    ** frame pWal->hdr.mxFrame - then the client would incorrectly assume
+    ** that it can read version A from the database file. However, since
+    ** we can guarantee that the checkpointer that set nBackfill could not
+    ** see any pages past pWal->hdr.mxFrame, this problem does not come up.
     */
+    pWal->minFrame = pInfo->nBackfill+1;
     walShmBarrier(pWal);
     if( pInfo->aReadMark[mxI]!=mxReadMark
      || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
@@ -51984,6 +52689,7 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
   u32 iRead = 0;                  /* If !=0, WAL frame to return data from */
   u32 iLast = pWal->hdr.mxFrame;  /* Last page in WAL for this reader */
   int iHash;                      /* Used to loop through N hash tables */
+  int iMinHash;
 
   /* This routine is only be called from within a read transaction. */
   assert( pWal->readLock>=0 || pWal->lockError );
@@ -52024,7 +52730,8 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
   **     This condition filters out entries that were added to the hash
   **     table after the current read-transaction had started.
   */
-  for(iHash=walFramePage(iLast); iHash>=0 && iRead==0; iHash--){
+  iMinHash = walFramePage(pWal->minFrame);
+  for(iHash=walFramePage(iLast); iHash>=iMinHash && iRead==0; iHash--){
     volatile ht_slot *aHash;      /* Pointer to hash table */
     volatile u32 *aPgno;          /* Pointer to array of page numbers */
     u32 iZero;                    /* Frame number corresponding to aPgno[0] */
@@ -52039,7 +52746,7 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
     nCollide = HASHTABLE_NSLOT;
     for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
       u32 iFrame = aHash[iKey] + iZero;
-      if( iFrame<=iLast && aPgno[aHash[iKey]]==pgno ){
+      if( iFrame<=iLast && iFrame>=pWal->minFrame && aPgno[aHash[iKey]]==pgno ){
         assert( iFrame>iRead || CORRUPT_DB );
         iRead = iFrame;
       }
@@ -52056,7 +52763,8 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
   {
     u32 iRead2 = 0;
     u32 iTest;
-    for(iTest=iLast; iTest>0; iTest--){
+    assert( pWal->minFrame>0 );
+    for(iTest=iLast; iTest>=pWal->minFrame; iTest--){
       if( walFramePgno(pWal, iTest)==pgno ){
         iRead2 = iTest;
         break;
@@ -53496,9 +54204,11 @@ struct IntegrityCk {
 */
 #if SQLITE_BYTEORDER==4321
 # define get2byteAligned(x)  (*(u16*)(x))
-#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4008000
+#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
+    && GCC_VERSION>=4008000
 # define get2byteAligned(x)  __builtin_bswap16(*(u16*)(x))
-#elif SQLITE_BYTEORDER==1234 && defined(_MSC_VER) && _MSC_VER>=1300
+#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
+    && defined(_MSC_VER) && _MSC_VER>=1300
 # define get2byteAligned(x)  _byteswap_ushort(*(u16*)(x))
 #else
 # define get2byteAligned(x)  ((x)[0]<<8 | (x)[1])
@@ -54385,26 +55095,25 @@ static void btreeReleaseAllCursorPages(BtCursor *pCur){
   pCur->iPage = -1;
 }
 
-
 /*
-** Save the current cursor position in the variables BtCursor.nKey 
-** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK.
+** The cursor passed as the only argument must point to a valid entry
+** when this function is called (i.e. have eState==CURSOR_VALID). This
+** function saves the current cursor key in variables pCur->nKey and
+** pCur->pKey. SQLITE_OK is returned if successful or an SQLite error 
+** code otherwise.
 **
-** The caller must ensure that the cursor is valid (has eState==CURSOR_VALID)
-** prior to calling this routine.  
+** If the cursor is open on an intkey table, then the integer key
+** (the rowid) is stored in pCur->nKey and pCur->pKey is left set to
+** NULL. If the cursor is open on a non-intkey table, then pCur->pKey is 
+** set to point to a malloced buffer pCur->nKey bytes in size containing 
+** the key.
 */
-static int saveCursorPosition(BtCursor *pCur){
+static int saveCursorKey(BtCursor *pCur){
   int rc;
-
-  assert( CURSOR_VALID==pCur->eState || CURSOR_SKIPNEXT==pCur->eState );
+  assert( CURSOR_VALID==pCur->eState );
   assert( 0==pCur->pKey );
   assert( cursorHoldsMutex(pCur) );
 
-  if( pCur->eState==CURSOR_SKIPNEXT ){
-    pCur->eState = CURSOR_VALID;
-  }else{
-    pCur->skipNext = 0;
-  }
   rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
   assert( rc==SQLITE_OK );  /* KeySize() cannot fail */
 
@@ -54412,8 +55121,7 @@ static int saveCursorPosition(BtCursor *pCur){
   ** stores the integer key in pCur->nKey. In this case this value is
   ** all that is required. Otherwise, if pCur is not open on an intKey
   ** table, then malloc space for and store the pCur->nKey bytes of key 
-  ** data.
-  */
+  ** data.  */
   if( 0==pCur->curIntKey ){
     void *pKey = sqlite3Malloc( pCur->nKey );
     if( pKey ){
@@ -54428,13 +55136,36 @@ static int saveCursorPosition(BtCursor *pCur){
     }
   }
   assert( !pCur->curIntKey || !pCur->pKey );
+  return rc;
+}
 
+/*
+** Save the current cursor position in the variables BtCursor.nKey 
+** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK.
+**
+** The caller must ensure that the cursor is valid (has eState==CURSOR_VALID)
+** prior to calling this routine.  
+*/
+static int saveCursorPosition(BtCursor *pCur){
+  int rc;
+
+  assert( CURSOR_VALID==pCur->eState || CURSOR_SKIPNEXT==pCur->eState );
+  assert( 0==pCur->pKey );
+  assert( cursorHoldsMutex(pCur) );
+
+  if( pCur->eState==CURSOR_SKIPNEXT ){
+    pCur->eState = CURSOR_VALID;
+  }else{
+    pCur->skipNext = 0;
+  }
+
+  rc = saveCursorKey(pCur);
   if( rc==SQLITE_OK ){
     btreeReleaseAllCursorPages(pCur);
     pCur->eState = CURSOR_REQUIRESEEK;
   }
 
-  invalidateOverflowCache(pCur);
+  pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl|BTCF_AtLast);
   return rc;
 }
 
@@ -60272,7 +61003,13 @@ static int pageInsertArray(
       if( pData<pBegin ) return 1;
       pSlot = pData;
     }
-    memcpy(pSlot, pCArray->apCell[i], sz);
+    /* pSlot and pCArray->apCell[i] will never overlap on a well-formed
+    ** database.  But they might for a corrupt database.  Hence use memmove()
+    ** since memcpy() sends SIGABORT with overlapping buffers on OpenBSD */
+    assert( (pSlot+sz)<=pCArray->apCell[i]
+         || pSlot>=(pCArray->apCell[i]+sz)
+         || CORRUPT_DB );
+    memmove(pSlot, pCArray->apCell[i], sz);
     put2byte(pCellptr, (pSlot - aData));
     pCellptr += 2;
   }
@@ -61397,7 +62134,7 @@ static int balance_nonroot(
     ** by smaller than the child due to the database header, and so all the
     ** free space needs to be up front.
     */
-    assert( nNew==1 );
+    assert( nNew==1 || CORRUPT_DB );
     rc = defragmentPage(apNew[0]);
     testcase( rc!=SQLITE_OK );
     assert( apNew[0]->nFree == 
@@ -61820,10 +62557,15 @@ end_insert:
 }
 
 /*
-** Delete the entry that the cursor is pointing to.  The cursor
-** is left pointing at an arbitrary location.
+** Delete the entry that the cursor is pointing to. 
+**
+** If the second parameter is zero, then the cursor is left pointing at an
+** arbitrary location after the delete. If it is non-zero, then the cursor 
+** is left in a state such that the next call to BtreeNext() or BtreePrev()
+** moves it to the same row as it would if the call to BtreeDelete() had
+** been omitted.
 */
-SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
+SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, int bPreserve){
   Btree *p = pCur->pBtree;
   BtShared *pBt = p->pBt;              
   int rc;                              /* Return code */
@@ -61832,6 +62574,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
   int iCellIdx;                        /* Index of cell to delete */
   int iCellDepth;                      /* Depth of node containing pCell */ 
   u16 szCell;                          /* Size of the cell being deleted */
+  int bSkipnext = 0;                   /* Leaf cursor in SKIPNEXT state */
 
   assert( cursorHoldsMutex(pCur) );
   assert( pBt->inTransaction==TRANS_WRITE );
@@ -61861,10 +62604,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
   }
 
   /* Save the positions of any other cursors open on this table before
-  ** making any modifications. Make the page containing the entry to be 
-  ** deleted writable. Then free any overflow pages associated with the 
-  ** entry and finally remove the cell itself from within the page.  
-  */
+  ** making any modifications.  */
   if( pCur->curFlags & BTCF_Multiple ){
     rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur);
     if( rc ) return rc;
@@ -61876,6 +62616,31 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
     invalidateIncrblobCursors(p, pCur->info.nKey, 0);
   }
 
+  /* If the bPreserve flag is set to true, then the cursor position must
+  ** be preserved following this delete operation. If the current delete
+  ** will cause a b-tree rebalance, then this is done by saving the cursor
+  ** key and leaving the cursor in CURSOR_REQUIRESEEK state before 
+  ** returning. 
+  **
+  ** Or, if the current delete will not cause a rebalance, then the cursor
+  ** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
+  ** before or after the deleted entry. In this case set bSkipnext to true.  */
+  if( bPreserve ){
+    if( !pPage->leaf 
+     || (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
+    ){
+      /* A b-tree rebalance will be required after deleting this entry.
+      ** Save the cursor key.  */
+      rc = saveCursorKey(pCur);
+      if( rc ) return rc;
+    }else{
+      bSkipnext = 1;
+    }
+  }
+
+  /* Make the page containing the entry to be deleted writable. Then free any
+  ** overflow pages associated with the entry and finally remove the cell
+  ** itself from within the page.  */
   rc = sqlite3PagerWrite(pPage->pDbPage);
   if( rc ) return rc;
   rc = clearCell(pPage, pCell, &szCell);
@@ -61929,7 +62694,23 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur){
   }
 
   if( rc==SQLITE_OK ){
-    moveToRoot(pCur);
+    if( bSkipnext ){
+      assert( bPreserve && pCur->iPage==iCellDepth );
+      assert( pPage==pCur->apPage[pCur->iPage] );
+      assert( (pPage->nCell>0 || CORRUPT_DB) && iCellIdx<=pPage->nCell );
+      pCur->eState = CURSOR_SKIPNEXT;
+      if( iCellIdx>=pPage->nCell ){
+        pCur->skipNext = -1;
+        pCur->aiIdx[iCellDepth] = pPage->nCell-1;
+      }else{
+        pCur->skipNext = 1;
+      }
+    }else{
+      rc = moveToRoot(pCur);
+      if( bPreserve ){
+        pCur->eState = CURSOR_REQUIRESEEK;
+      }
+    }
   }
   return rc;
 }
@@ -62494,7 +63275,6 @@ static void checkAppendMsg(
   ...
 ){
   va_list ap;
-  char zBuf[200];
   if( !pCheck->mxErr ) return;
   pCheck->mxErr--;
   pCheck->nErr++;
@@ -62503,8 +63283,7 @@ static void checkAppendMsg(
     sqlite3StrAccumAppend(&pCheck->errMsg, "\n", 1);
   }
   if( pCheck->zPfx ){
-    sqlite3_snprintf(sizeof(zBuf), zBuf, pCheck->zPfx, pCheck->v1, pCheck->v2);
-    sqlite3StrAccumAppendAll(&pCheck->errMsg, zBuf);
+    sqlite3XPrintf(&pCheck->errMsg, 0, pCheck->zPfx, pCheck->v1, pCheck->v2);
   }
   sqlite3VXPrintf(&pCheck->errMsg, 1, zFormat, ap);
   va_end(ap);
@@ -62653,6 +63432,10 @@ static void checkList(
 #endif
     iPage = get4byte(pOvflData);
     sqlite3PagerUnref(pOvflPage);
+
+    if( isFreeList && N<(iPage!=0) ){
+      checkAppendMsg(pCheck, "free-page count in header is too small");
+    }
   }
 }
 #endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@@ -64146,6 +64929,10 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
   b.pDest = pTo;
   b.iNext = 1;
 
+#ifdef SQLITE_HAS_CODEC
+  sqlite3PagerAlignReserve(sqlite3BtreePager(pTo), sqlite3BtreePager(pFrom));
+#endif
+
   /* 0x7FFFFFFF is the hard limit for the number of pages in a database
   ** file. By passing this as the number of pages to copy to
   ** sqlite3_backup_step(), we can guarantee that the copy finishes 
@@ -65329,7 +66116,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
 ** to be a scalar SQL function. If
 **
 **   * all function arguments are SQL literals,
-**   * the SQLITE_FUNC_CONSTANT function flag is set, and
+**   * one of the SQLITE_FUNC_CONSTANT or _SLOCHNG function flags is set, and
 **   * the SQLITE_FUNC_NEEDCOLL function flag is not set,
 **
 ** then this routine attempts to invoke the SQL function. Assuming no
@@ -65370,7 +66157,7 @@ static int valueFromFunction(
   nName = sqlite3Strlen30(p->u.zToken);
   pFunc = sqlite3FindFunction(db, p->u.zToken, nName, nVal, enc, 0);
   assert( pFunc );
-  if( (pFunc->funcFlags & SQLITE_FUNC_CONSTANT)==0 
+  if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0 
    || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
   ){
     return SQLITE_OK;
@@ -65964,7 +66751,7 @@ SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepa
 */
 SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt){
   Vdbe *p = (Vdbe *)pStmt;
-  return (p && p->isPrepareV2) ? p->zSql : 0;
+  return p ? p->zSql : 0;
 }
 
 /*
@@ -66111,6 +66898,44 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe *p, int op, int p1, int p2){
   return sqlite3VdbeAddOp3(p, op, p1, p2, 0);
 }
 
+/* Generate code for an unconditional jump to instruction iDest
+*/
+SQLITE_PRIVATE int sqlite3VdbeGoto(Vdbe *p, int iDest){
+  return sqlite3VdbeAddOp3(p, OP_Goto, 0, iDest, 0);
+}
+
+/* Generate code to cause the string zStr to be loaded into
+** register iDest
+*/
+SQLITE_PRIVATE int sqlite3VdbeLoadString(Vdbe *p, int iDest, const char *zStr){
+  return sqlite3VdbeAddOp4(p, OP_String8, 0, iDest, 0, zStr, 0);
+}
+
+/*
+** Generate code that initializes multiple registers to string or integer
+** constants.  The registers begin with iDest and increase consecutively.
+** One register is initialized for each characgter in zTypes[].  For each
+** "s" character in zTypes[], the register is a string if the argument is
+** not NULL, or OP_Null if the value is a null pointer.  For each "i" character
+** in zTypes[], the register is initialized to an integer.
+*/
+SQLITE_PRIVATE void sqlite3VdbeMultiLoad(Vdbe *p, int iDest, const char *zTypes, ...){
+  va_list ap;
+  int i;
+  char c;
+  va_start(ap, zTypes);
+  for(i=0; (c = zTypes[i])!=0; i++){
+    if( c=='s' ){
+      const char *z = va_arg(ap, const char*);
+      int addr = sqlite3VdbeAddOp2(p, z==0 ? OP_Null : OP_String8, 0, iDest++);
+      if( z ) sqlite3VdbeChangeP4(p, addr, z, 0);
+    }else{
+      assert( c=='i' );
+      sqlite3VdbeAddOp2(p, OP_Integer, va_arg(ap, int), iDest++);
+    }
+  }
+  va_end(ap);
+}
 
 /*
 ** Add an opcode that includes the p4 value as a pointer.
@@ -66130,7 +66955,8 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4(
 }
 
 /*
-** Add an opcode that includes the p4 value with a P4_INT64 type.
+** Add an opcode that includes the p4 value with a P4_INT64 or
+** P4_REAL type.
 */
 SQLITE_PRIVATE int sqlite3VdbeAddOp4Dup8(
   Vdbe *p,            /* Add the opcode to this VM */
@@ -66215,7 +67041,8 @@ SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){
   int j = -1-x;
   assert( v->magic==VDBE_MAGIC_INIT );
   assert( j<p->nLabel );
-  if( ALWAYS(j>=0) && p->aLabel ){
+  assert( j>=0 );
+  if( p->aLabel ){
     p->aLabel[j] = v->nOp;
   }
   p->iFixedOp = v->nOp - 1;
@@ -66359,17 +67186,21 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
 #endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */
 
 /*
-** Loop through the program looking for P2 values that are negative
-** on jump instructions.  Each such value is a label.  Resolve the
-** label by setting the P2 value to its correct non-zero value.
+** This routine is called after all opcodes have been inserted.  It loops
+** through all the opcodes and fixes up some details.
 **
-** This routine is called once after all opcodes have been inserted.
+** (1) For each jump instruction with a negative P2 value (a label)
+**     resolve the P2 value to an actual address.
 **
-** Variable *pMaxFuncArgs is set to the maximum value of any P2 argument 
-** to an OP_Function, OP_AggStep or OP_VFilter opcode. This is used by 
-** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array.
+** (2) Compute the maximum number of arguments used by any SQL function
+**     and store that value in *pMaxFuncArgs.
 **
-** The Op.opflags field is set on all opcodes.
+** (3) Update the Vdbe.readOnly and Vdbe.bIsReader flags to accurately
+**     indicate what the prepared statement actually does.
+**
+** (4) Initialize the p4.xAdvance pointer on opcodes that use it.
+**
+** (5) Reclaim the memory allocated for storing labels.
 */
 static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
   int i;
@@ -66482,46 +67313,44 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg)
 ** address of the first operation added.
 */
 SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp, int iLineno){
-  int addr;
+  int addr, i;
+  VdbeOp *pOut;
+  assert( nOp>0 );
   assert( p->magic==VDBE_MAGIC_INIT );
   if( p->nOp + nOp > p->pParse->nOpAlloc && growOpArray(p, nOp) ){
     return 0;
   }
   addr = p->nOp;
-  if( ALWAYS(nOp>0) ){
-    int i;
-    VdbeOpList const *pIn = aOp;
-    for(i=0; i<nOp; i++, pIn++){
-      int p2 = pIn->p2;
-      VdbeOp *pOut = &p->aOp[i+addr];
-      pOut->opcode = pIn->opcode;
-      pOut->p1 = pIn->p1;
-      if( p2<0 ){
-        assert( sqlite3OpcodeProperty[pOut->opcode] & OPFLG_JUMP );
-        pOut->p2 = addr + ADDR(p2);
-      }else{
-        pOut->p2 = p2;
-      }
-      pOut->p3 = pIn->p3;
-      pOut->p4type = P4_NOTUSED;
-      pOut->p4.p = 0;
-      pOut->p5 = 0;
+  pOut = &p->aOp[addr];
+  for(i=0; i<nOp; i++, aOp++, pOut++){
+    int p2 = aOp->p2;
+    pOut->opcode = aOp->opcode;
+    pOut->p1 = aOp->p1;
+    if( p2<0 ){
+      assert( sqlite3OpcodeProperty[pOut->opcode] & OPFLG_JUMP );
+      pOut->p2 = addr + ADDR(p2);
+    }else{
+      pOut->p2 = p2;
+    }
+    pOut->p3 = aOp->p3;
+    pOut->p4type = P4_NOTUSED;
+    pOut->p4.p = 0;
+    pOut->p5 = 0;
 #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
-      pOut->zComment = 0;
+    pOut->zComment = 0;
 #endif
 #ifdef SQLITE_VDBE_COVERAGE
-      pOut->iSrcLine = iLineno+i;
+    pOut->iSrcLine = iLineno+i;
 #else
-      (void)iLineno;
+    (void)iLineno;
 #endif
 #ifdef SQLITE_DEBUG
-      if( p->db->flags & SQLITE_VdbeAddopTrace ){
-        sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]);
-      }
-#endif
+    if( p->db->flags & SQLITE_VdbeAddopTrace ){
+      sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]);
     }
-    p->nOp += nOp;
+#endif
   }
+  p->nOp += nOp;
   return addr;
 }
 
@@ -66554,49 +67383,23 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(
 
 
 /*
-** Change the value of the P1 operand for a specific instruction.
-** This routine is useful when a large program is loaded from a
-** static array using sqlite3VdbeAddOpList but we want to make a
-** few minor changes to the program.
+** Change the value of the opcode, or P1, P2, P3, or P5 operands
+** for a specific instruction.
 */
+SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe *p, u32 addr, u8 iNewOpcode){
+  sqlite3VdbeGetOp(p,addr)->opcode = iNewOpcode;
+}
 SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe *p, u32 addr, int val){
-  assert( p!=0 );
-  if( ((u32)p->nOp)>addr ){
-    p->aOp[addr].p1 = val;
-  }
+  sqlite3VdbeGetOp(p,addr)->p1 = val;
 }
-
-/*
-** Change the value of the P2 operand for a specific instruction.
-** This routine is useful for setting a jump destination.
-*/
 SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe *p, u32 addr, int val){
-  assert( p!=0 );
-  if( ((u32)p->nOp)>addr ){
-    p->aOp[addr].p2 = val;
-  }
+  sqlite3VdbeGetOp(p,addr)->p2 = val;
 }
-
-/*
-** Change the value of the P3 operand for a specific instruction.
-*/
 SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, u32 addr, int val){
-  assert( p!=0 );
-  if( ((u32)p->nOp)>addr ){
-    p->aOp[addr].p3 = val;
-  }
+  sqlite3VdbeGetOp(p,addr)->p3 = val;
 }
-
-/*
-** Change the value of the P5 operand for the most recently
-** added operation.
-*/
-SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u8 val){
-  assert( p!=0 );
-  if( p->aOp ){
-    assert( p->nOp>0 );
-    p->aOp[p->nOp-1].p5 = val;
-  }
+SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u8 p5){
+  sqlite3VdbeGetOp(p,-1)->p5 = p5;
 }
 
 /*
@@ -66604,8 +67407,8 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u8 val){
 ** the address of the next instruction to be coded.
 */
 SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){
-  sqlite3VdbeChangeP2(p, addr, p->nOp);
   p->pParse->iFixedOp = p->nOp - 1;
+  sqlite3VdbeChangeP2(p, addr, p->nOp);
 }
 
 
@@ -66990,8 +67793,9 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
           zColl = "B";
           n = 1;
         }
-        if( i+n>nTemp-6 ){
+        if( i+n>nTemp-7 ){
           memcpy(&zTemp[i],",...",4);
+          i += 4;
           break;
         }
         zTemp[i++] = ',';
@@ -70332,6 +71136,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value *pVal){
 SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value *pVal){
   return sqlite3VdbeIntValue((Mem*)pVal);
 }
+SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value *pVal){
+  return ((Mem*)pVal)->eSubtype;
+}
 SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value *pVal){
   return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8);
 }
@@ -70510,6 +71317,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context *pCtx){
   assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
   sqlite3VdbeMemSetNull(pCtx->pOut);
 }
+SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){
+  assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
+  pCtx->pOut->eSubtype = eSubtype & 0xff;
+}
 SQLITE_API void SQLITE_STDCALL sqlite3_result_text(
   sqlite3_context *pCtx, 
   const char *z, 
@@ -70756,7 +71567,7 @@ end_of_step:
   ** were called on statement p.
   */
   assert( rc==SQLITE_ROW  || rc==SQLITE_DONE   || rc==SQLITE_ERROR 
-       || rc==SQLITE_BUSY || rc==SQLITE_MISUSE
+       || (rc&0xff)==SQLITE_BUSY || rc==SQLITE_MISUSE
   );
   assert( (p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE) || p->rc==p->rcApp );
   if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
@@ -70841,7 +71652,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context *p){
 ** application defined function.
 */
 SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context *p){
-  assert( p && p->pFunc );
+  assert( p && p->pOut );
   return p->pOut->db;
 }
 
@@ -71050,18 +71861,19 @@ static const Mem *columnNullValue(void){
 #endif
     = {
         /* .u          = */ {0},
-        /* .flags      = */ MEM_Null,
-        /* .enc        = */ 0,
-        /* .n          = */ 0,
-        /* .z          = */ 0,
-        /* .zMalloc    = */ 0,
-        /* .szMalloc   = */ 0,
-        /* .iPadding1  = */ 0,
-        /* .db         = */ 0,
-        /* .xDel       = */ 0,
+        /* .flags      = */ (u16)MEM_Null,
+        /* .enc        = */ (u8)0,
+        /* .eSubtype   = */ (u8)0,
+        /* .n          = */ (int)0,
+        /* .z          = */ (char*)0,
+        /* .zMalloc    = */ (char*)0,
+        /* .szMalloc   = */ (int)0,
+        /* .uTemp      = */ (u32)0,
+        /* .db         = */ (sqlite3*)0,
+        /* .xDel       = */ (void(*)(void*))0,
 #ifdef SQLITE_DEBUG
-        /* .pScopyFrom = */ 0,
-        /* .pFiller    = */ 0,
+        /* .pScopyFrom = */ (Mem*)0,
+        /* .pFiller    = */ (void*)0,
 #endif
       };
   return &nullMem;
@@ -72659,7 +73471,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
     ** sqlite3_column_text16() failed.  */
     goto no_mem;
   }
-  assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY );
+  assert( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_BUSY );
   assert( p->bIsReader || p->readOnly!=0 );
   p->rc = SQLITE_OK;
   p->iCurrentTime = 0;
@@ -75096,12 +75908,12 @@ case OP_AutoCommit: {
       goto vdbe_return;
     }else{
       db->autoCommit = (u8)desiredAutoCommit;
-      if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
-        p->pc = (int)(pOp - aOp);
-        db->autoCommit = (u8)(1-desiredAutoCommit);
-        p->rc = rc = SQLITE_BUSY;
-        goto vdbe_return;
-      }
+    }
+    if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
+      p->pc = (int)(pOp - aOp);
+      db->autoCommit = (u8)(1-desiredAutoCommit);
+      p->rc = rc = SQLITE_BUSY;
+      goto vdbe_return;
     }
     assert( db->nStatement==0 );
     sqlite3CloseSavepoints(db);
@@ -75173,9 +75985,11 @@ case OP_Transaction: {
 
   if( pBt ){
     rc = sqlite3BtreeBeginTrans(pBt, pOp->p2);
-    if( rc==SQLITE_BUSY ){
+    testcase( rc==SQLITE_BUSY_SNAPSHOT );
+    testcase( rc==SQLITE_BUSY_RECOVERY );
+    if( (rc&0xff)==SQLITE_BUSY ){
       p->pc = (int)(pOp - aOp);
-      p->rc = rc = SQLITE_BUSY;
+      p->rc = rc;
       goto vdbe_return;
     }
     if( rc!=SQLITE_OK ){
@@ -76054,9 +76868,10 @@ case OP_Found: {        /* jump, in3 */
 **
 ** P1 is the index of a cursor open on an SQL table btree (with integer
 ** keys).  P3 is an integer rowid.  If P1 does not contain a record with
-** rowid P3 then jump immediately to P2.  If P1 does contain a record
-** with rowid P3 then leave the cursor pointing at that record and fall
-** through to the next instruction.
+** rowid P3 then jump immediately to P2.  Or, if P2 is 0, raise an
+** SQLITE_CORRUPT error. If P1 does contain a record with rowid P3 then 
+** leave the cursor pointing at that record and fall through to the next
+** instruction.
 **
 ** The OP_NotFound opcode performs the same operation on index btrees
 ** (with arbitrary multi-value keys).
@@ -76088,13 +76903,21 @@ case OP_NotExists: {        /* jump, in3 */
   res = 0;
   iKey = pIn3->u.i;
   rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res);
+  assert( rc==SQLITE_OK || res==0 );
   pC->movetoTarget = iKey;  /* Used by OP_Delete */
   pC->nullRow = 0;
   pC->cacheStatus = CACHE_STALE;
   pC->deferredMoveto = 0;
   VdbeBranchTaken(res!=0,2);
   pC->seekResult = res;
-  if( res!=0 ) goto jump_to_p2;
+  if( res!=0 ){
+    assert( rc==SQLITE_OK );
+    if( pOp->p2==0 ){
+      rc = SQLITE_CORRUPT_BKPT;
+    }else{
+      goto jump_to_p2;
+    }
+  }
   break;
 }
 
@@ -76360,14 +77183,15 @@ case OP_InsertInt: {
   break;
 }
 
-/* Opcode: Delete P1 P2 * P4 *
+/* Opcode: Delete P1 P2 * P4 P5
 **
 ** Delete the record at which the P1 cursor is currently pointing.
 **
-** The cursor will be left pointing at either the next or the previous
-** record in the table. If it is left pointing at the next record, then
-** the next Next instruction will be a no-op.  Hence it is OK to delete
-** a record from within a Next loop.
+** If the P5 parameter is non-zero, the cursor will be left pointing at 
+** either the next or the previous record in the table. If it is left 
+** pointing at the next record, then the next Next instruction will be a 
+** no-op. As a result, in this case it is OK to delete a record from within a
+** Next loop. If P5 is zero, then the cursor is left in an undefined state.
 **
 ** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is
 ** incremented (otherwise not).
@@ -76382,6 +77206,7 @@ case OP_InsertInt: {
 */
 case OP_Delete: {
   VdbeCursor *pC;
+  u8 hasUpdateCallback;
 
   assert( pOp->p1>=0 && pOp->p1<p->nCursor );
   pC = p->apCsr[pOp->p1];
@@ -76389,22 +77214,27 @@ case OP_Delete: {
   assert( pC->pCursor!=0 );  /* Only valid for real tables, no pseudotables */
   assert( pC->deferredMoveto==0 );
 
+  hasUpdateCallback = db->xUpdateCallback && pOp->p4.z && pC->isTable;
+  if( pOp->p5 && hasUpdateCallback ){
+    sqlite3BtreeKeySize(pC->pCursor, &pC->movetoTarget);
+  }
+
 #ifdef SQLITE_DEBUG
   /* The seek operation that positioned the cursor prior to OP_Delete will
   ** have also set the pC->movetoTarget field to the rowid of the row that
   ** is being deleted */
-  if( pOp->p4.z && pC->isTable ){
+  if( pOp->p4.z && pC->isTable && pOp->p5==0 ){
     i64 iKey = 0;
     sqlite3BtreeKeySize(pC->pCursor, &iKey);
     assert( pC->movetoTarget==iKey ); 
   }
 #endif
  
-  rc = sqlite3BtreeDelete(pC->pCursor);
+  rc = sqlite3BtreeDelete(pC->pCursor, pOp->p5);
   pC->cacheStatus = CACHE_STALE;
 
   /* Invoke the update-hook if required. */
-  if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z && pC->isTable ){
+  if( rc==SQLITE_OK && hasUpdateCallback ){
     db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE,
                         db->aDb[pC->iDb].zName, pOp->p4.z, pC->movetoTarget);
     assert( pC->iDb>=0 );
@@ -76943,7 +77773,7 @@ case OP_IdxDelete: {
 #endif
   rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res);
   if( rc==SQLITE_OK && res==0 ){
-    rc = sqlite3BtreeDelete(pCrsr);
+    rc = sqlite3BtreeDelete(pCrsr, 0);
   }
   assert( pC->deferredMoveto==0 );
   pC->cacheStatus = CACHE_STALE;
@@ -77741,12 +78571,12 @@ case OP_MemMax: {        /* in2 */
 }
 #endif /* SQLITE_OMIT_AUTOINCREMENT */
 
-/* Opcode: IfPos P1 P2 * * *
-** Synopsis: if r[P1]>0 goto P2
+/* Opcode: IfPos P1 P2 P3 * *
+** Synopsis: if r[P1]>0 then r[P1]-=P3, goto P2
 **
 ** Register P1 must contain an integer.
-** If the value of register P1 is 1 or greater, jump to P2 and
-** add the literal value P3 to register P1.
+** If the value of register P1 is 1 or greater, subtract P3 from the
+** value in P1 and jump to P2.
 **
 ** If the initial value of register P1 is less than 1, then the
 ** value is unchanged and control passes through to the next instruction.
@@ -77755,38 +78585,44 @@ case OP_IfPos: {        /* jump, in1 */
   pIn1 = &aMem[pOp->p1];
   assert( pIn1->flags&MEM_Int );
   VdbeBranchTaken( pIn1->u.i>0, 2);
-  if( pIn1->u.i>0 ) goto jump_to_p2;
+  if( pIn1->u.i>0 ){
+    pIn1->u.i -= pOp->p3;
+    goto jump_to_p2;
+  }
   break;
 }
 
-/* Opcode: IfNeg P1 P2 P3 * *
-** Synopsis: r[P1]+=P3, if r[P1]<0 goto P2
+/* Opcode: SetIfNotPos P1 P2 P3 * *
+** Synopsis: if r[P1]<=0 then r[P2]=P3
 **
-** Register P1 must contain an integer.  Add literal P3 to the value in
-** register P1 then if the value of register P1 is less than zero, jump to P2. 
+** Register P1 must contain an integer.
+** If the value of register P1 is not positive (if it is less than 1) then
+** set the value of register P2 to be the integer P3.
 */
-case OP_IfNeg: {        /* jump, in1 */
+case OP_SetIfNotPos: {        /* in1, in2 */
   pIn1 = &aMem[pOp->p1];
   assert( pIn1->flags&MEM_Int );
-  pIn1->u.i += pOp->p3;
-  VdbeBranchTaken(pIn1->u.i<0, 2);
-  if( pIn1->u.i<0 ) goto jump_to_p2;
+  if( pIn1->u.i<=0 ){
+    pOut = out2Prerelease(p, pOp);
+    pOut->u.i = pOp->p3;
+  }
   break;
 }
 
 /* Opcode: IfNotZero P1 P2 P3 * *
-** Synopsis: if r[P1]!=0 then r[P1]+=P3, goto P2
+** Synopsis: if r[P1]!=0 then r[P1]-=P3, goto P2
 **
 ** Register P1 must contain an integer.  If the content of register P1 is
-** initially nonzero, then add P3 to P1 and jump to P2.  If register P1 is
-** initially zero, leave it unchanged and fall through.
+** initially nonzero, then subtract P3 from the value in register P1 and
+** jump to P2.  If register P1 is initially zero, leave it unchanged
+** and fall through.
 */
 case OP_IfNotZero: {        /* jump, in1 */
   pIn1 = &aMem[pOp->p1];
   assert( pIn1->flags&MEM_Int );
   VdbeBranchTaken(pIn1->u.i<0, 2);
   if( pIn1->u.i ){
-     pIn1->u.i += pOp->p3;
+     pIn1->u.i -= pOp->p3;
      goto jump_to_p2;
   }
   break;
@@ -79011,7 +79847,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
       for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
         int j;
         for(j=0; j<pIdx->nKeyCol; j++){
-          if( pIdx->aiColumn[j]==iCol ){
+          /* FIXME: Be smarter about indexes that use expressions */
+          if( pIdx->aiColumn[j]==iCol || pIdx->aiColumn[j]==XN_EXPR ){
             zFault = "indexed";
           }
         }
@@ -82592,6 +83429,11 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
       if( sqlite3WalkSelect(pWalker, pItem->pSelect) ){
         return WRC_Abort;
       }
+      if( pItem->fg.isTabFunc
+       && sqlite3WalkExprList(pWalker, pItem->u1.pFuncArg)
+      ){
+        return WRC_Abort;
+      }
     }
   }
   return WRC_Continue;
@@ -82689,30 +83531,6 @@ static void incrAggFunctionDepth(Expr *pExpr, int N){
 ** Turn the pExpr expression into an alias for the iCol-th column of the
 ** result set in pEList.
 **
-** If the result set column is a simple column reference, then this routine
-** makes an exact copy.  But for any other kind of expression, this
-** routine make a copy of the result set column as the argument to the
-** TK_AS operator.  The TK_AS operator causes the expression to be
-** evaluated just once and then reused for each alias.
-**
-** The reason for suppressing the TK_AS term when the expression is a simple
-** column reference is so that the column reference will be recognized as
-** usable by indices within the WHERE clause processing logic. 
-**
-** The TK_AS operator is inhibited if zType[0]=='G'.  This means
-** that in a GROUP BY clause, the expression is evaluated twice.  Hence:
-**
-**     SELECT random()%5 AS x, count(*) FROM tab GROUP BY x
-**
-** Is equivalent to:
-**
-**     SELECT random()%5 AS x, count(*) FROM tab GROUP BY random()%5
-**
-** The result of random()%5 in the GROUP BY clause is probably different
-** from the result in the result-set.  On the other hand Standard SQL does
-** not allow the GROUP BY clause to contain references to result-set columns.
-** So this should never come up in well-formed queries.
-**
 ** If the reference is followed by a COLLATE operator, then make sure
 ** the COLLATE operator is preserved.  For example:
 **
@@ -82746,19 +83564,11 @@ static void resolveAlias(
   db = pParse->db;
   pDup = sqlite3ExprDup(db, pOrig, 0);
   if( pDup==0 ) return;
-  if( pOrig->op!=TK_COLUMN && zType[0]!='G' ){
-    incrAggFunctionDepth(pDup, nSubquery);
-    pDup = sqlite3PExpr(pParse, TK_AS, pDup, 0, 0);
-    if( pDup==0 ) return;
-    ExprSetProperty(pDup, EP_Skip);
-    if( pEList->a[iCol].u.x.iAlias==0 ){
-      pEList->a[iCol].u.x.iAlias = (u16)(++pParse->nAlias);
-    }
-    pDup->iTable = pEList->a[iCol].u.x.iAlias;
-  }
+  if( zType[0]!='G' ) incrAggFunctionDepth(pDup, nSubquery);
   if( pExpr->op==TK_COLLATE ){
     pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken);
   }
+  ExprSetProperty(pDup, EP_Alias);
 
   /* Before calling sqlite3ExprDelete(), set the EP_Static flag. This 
   ** prevents ExprDelete() from deleting the Expr structure itself,
@@ -82950,7 +83760,7 @@ static int lookupName(
             ** USING clause, then skip this match.
             */
             if( cnt==1 ){
-              if( pItem->jointype & JT_NATURAL ) continue;
+              if( pItem->fg.jointype & JT_NATURAL ) continue;
               if( nameInUsingClause(pItem->pUsing, zCol) ) continue;
             }
             cnt++;
@@ -82965,8 +83775,8 @@ static int lookupName(
         pExpr->iTable = pMatch->iCursor;
         pExpr->pTab = pMatch->pTab;
         /* RIGHT JOIN not (yet) supported */
-        assert( (pMatch->jointype & JT_RIGHT)==0 );
-        if( (pMatch->jointype & JT_LEFT)!=0 ){
+        assert( (pMatch->fg.jointype & JT_RIGHT)==0 );
+        if( (pMatch->fg.jointype & JT_LEFT)!=0 ){
           ExprSetProperty(pExpr, EP_CanBeNull);
         }
         pSchema = pExpr->pTab->pSchema;
@@ -83031,8 +83841,13 @@ static int lookupName(
     /*
     ** Perhaps the name is a reference to the ROWID
     */
-    if( cnt==0 && cntTab==1 && pMatch && sqlite3IsRowid(zCol)
-     && VisibleRowid(pMatch->pTab) ){
+    if( cnt==0
+     && cntTab==1
+     && pMatch
+     && (pNC->ncFlags & NC_IdxExpr)==0
+     && sqlite3IsRowid(zCol)
+     && VisibleRowid(pMatch->pTab)
+    ){
       cnt = 1;
       pExpr->iColumn = -1;     /* IMP: R-44911-55124 */
       pExpr->affinity = SQLITE_AFF_INTEGER;
@@ -83051,9 +83866,9 @@ static int lookupName(
     ** resolved by the time the WHERE clause is resolved.
     **
     ** The ability to use an output result-set column in the WHERE, GROUP BY,
-    ** or HAVING clauses, or as part of a larger expression in the ORDRE BY
+    ** or HAVING clauses, or as part of a larger expression in the ORDER BY
     ** clause is not standard SQL.  This is a (goofy) SQLite extension, that
-    ** is supported for backwards compatibility only.  TO DO: Issue a warning
+    ** is supported for backwards compatibility only. Hence, we issue a warning
     ** on sqlite3_log() whenever the capability is used.
     */
     if( (pEList = pNC->pEList)!=0
@@ -83150,7 +83965,7 @@ static int lookupName(
 lookupname_end:
   if( cnt==1 ){
     assert( pNC!=0 );
-    if( pExpr->op!=TK_AS ){
+    if( !ExprHasProperty(pExpr, EP_Alias) ){
       sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList);
     }
     /* Increment the nRef value on all name contexts from TopNC up to
@@ -83191,36 +84006,25 @@ SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSr
 }
 
 /*
-** Report an error that an expression is not valid for a partial index WHERE
-** clause.
+** Report an error that an expression is not valid for some set of
+** pNC->ncFlags values determined by validMask.
 */
-static void notValidPartIdxWhere(
+static void notValid(
   Parse *pParse,       /* Leave error message here */
   NameContext *pNC,    /* The name context */
-  const char *zMsg     /* Type of error */
+  const char *zMsg,    /* Type of error */
+  int validMask        /* Set of contexts for which prohibited */
 ){
-  if( (pNC->ncFlags & NC_PartIdx)!=0 ){
-    sqlite3ErrorMsg(pParse, "%s prohibited in partial index WHERE clauses",
-                    zMsg);
-  }
-}
-
+  assert( (validMask&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr))==0 );
+  if( (pNC->ncFlags & validMask)!=0 ){
+    const char *zIn = "partial index WHERE clauses";
+    if( pNC->ncFlags & NC_IdxExpr )      zIn = "index expressions";
 #ifndef SQLITE_OMIT_CHECK
-/*
-** Report an error that an expression is not valid for a CHECK constraint.
-*/
-static void notValidCheckConstraint(
-  Parse *pParse,       /* Leave error message here */
-  NameContext *pNC,    /* The name context */
-  const char *zMsg     /* Type of error */
-){
-  if( (pNC->ncFlags & NC_IsCheck)!=0 ){
-    sqlite3ErrorMsg(pParse,"%s prohibited in CHECK constraints", zMsg);
+    else if( pNC->ncFlags & NC_IsCheck ) zIn = "CHECK constraints";
+#endif
+    sqlite3ErrorMsg(pParse, "%s prohibited in %s", zMsg, zIn);
   }
 }
-#else
-# define notValidCheckConstraint(P,N,M)
-#endif
 
 /*
 ** Expression p should encode a floating point value between 1.0 and 0.0.
@@ -83305,6 +84109,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
       Expr *pRight;
 
       /* if( pSrcList==0 ) break; */
+      notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr);
+      /*notValid(pParse, pNC, "the \".\" operator", NC_PartIdx|NC_IsCheck, 1);*/
       pRight = pExpr->pRight;
       if( pRight->op==TK_ID ){
         zDb = 0;
@@ -83334,7 +84140,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
       u8 enc = ENC(pParse->db);   /* The database encoding */
 
       assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
-      notValidPartIdxWhere(pParse, pNC, "functions");
+      notValid(pParse, pNC, "functions", NC_PartIdx);
       zId = pExpr->u.zToken;
       nId = sqlite3Strlen30(zId);
       pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
@@ -83382,9 +84188,18 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
           return WRC_Prune;
         }
 #endif
-        if( pDef->funcFlags & SQLITE_FUNC_CONSTANT ){
+        if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){
+          /* For the purposes of the EP_ConstFunc flag, date and time
+          ** functions and other functions that change slowly are considered
+          ** constant because they are constant for the duration of one query */
           ExprSetProperty(pExpr,EP_ConstFunc);
         }
+        if( (pDef->funcFlags & SQLITE_FUNC_CONSTANT)==0 ){
+          /* Date/time functions that use 'now', and other functions like
+          ** sqlite_version() that might change over time cannot be used
+          ** in an index. */
+          notValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr);
+        }
       }
       if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
         sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
@@ -83430,8 +84245,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
       testcase( pExpr->op==TK_IN );
       if( ExprHasProperty(pExpr, EP_xIsSelect) ){
         int nRef = pNC->nRef;
-        notValidCheckConstraint(pParse, pNC, "subqueries");
-        notValidPartIdxWhere(pParse, pNC, "subqueries");
+        notValid(pParse, pNC, "subqueries", NC_IsCheck|NC_PartIdx|NC_IdxExpr);
         sqlite3WalkSelect(pWalker, pExpr->x.pSelect);
         assert( pNC->nRef>=nRef );
         if( nRef!=pNC->nRef ){
@@ -83441,8 +84255,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
       break;
     }
     case TK_VARIABLE: {
-      notValidCheckConstraint(pParse, pNC, "parameters");
-      notValidPartIdxWhere(pParse, pNC, "parameters");
+      notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr);
       break;
     }
   }
@@ -83786,7 +84599,6 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
   int isCompound;         /* True if p is a compound select */
   int nCompound;          /* Number of compound terms processed so far */
   Parse *pParse;          /* Parsing context */
-  ExprList *pEList;       /* Result set expression list */
   int i;                  /* Loop counter */
   ExprList *pGroupBy;     /* The GROUP BY clause */
   Select *pLeftmost;      /* Left-most of SELECT of a compound */
@@ -83859,7 +84671,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
         ** parent contexts. After resolving references to expressions in
         ** pItem->pSelect, check if this value has changed. If so, then
         ** SELECT statement pItem->pSelect must be correlated. Set the
-        ** pItem->isCorrelated flag if this is the case. */
+        ** pItem->fg.isCorrelated flag if this is the case. */
         for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef += pNC->nRef;
 
         if( pItem->zName ) pParse->zAuthContext = pItem->zName;
@@ -83868,8 +84680,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
         if( pParse->nErr || db->mallocFailed ) return WRC_Abort;
 
         for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef -= pNC->nRef;
-        assert( pItem->isCorrelated==0 && nRef<=0 );
-        pItem->isCorrelated = (nRef!=0);
+        assert( pItem->fg.isCorrelated==0 && nRef<=0 );
+        pItem->fg.isCorrelated = (nRef!=0);
       }
     }
   
@@ -83881,14 +84693,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
     sNC.pNext = pOuterNC;
   
     /* Resolve names in the result set. */
-    pEList = p->pEList;
-    assert( pEList!=0 );
-    for(i=0; i<pEList->nExpr; i++){
-      Expr *pX = pEList->a[i].pExpr;
-      if( sqlite3ResolveExprNames(&sNC, pX) ){
-        return WRC_Abort;
-      }
-    }
+    if( sqlite3ResolveExprListNames(&sNC, p->pEList) ) return WRC_Abort;
   
     /* If there are no aggregate functions in the result-set, and no GROUP BY 
     ** expression, do not allow aggregates in any of the other expressions.
@@ -83921,6 +84726,16 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
     if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
     if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort;
 
+    /* Resolve names in table-valued-function arguments */
+    for(i=0; i<p->pSrc->nSrc; i++){
+      struct SrcList_item *pItem = &p->pSrc->a[i];
+      if( pItem->fg.isTabFunc
+       && sqlite3ResolveExprListNames(&sNC, pItem->u1.pFuncArg) 
+      ){
+        return WRC_Abort;
+      }
+    }
+
     /* The ORDER BY and GROUP BY clauses may not refer to terms in
     ** outer queries 
     */
@@ -84084,6 +84899,22 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames(
   return ExprHasProperty(pExpr, EP_Error);
 }
 
+/*
+** Resolve all names for all expression in an expression list.  This is
+** just like sqlite3ResolveExprNames() except that it works for an expression
+** list rather than a single expression.
+*/
+SQLITE_PRIVATE int sqlite3ResolveExprListNames( 
+  NameContext *pNC,       /* Namespace to resolve expressions in. */
+  ExprList *pList         /* The expression list to be analyzed. */
+){
+  int i;
+  assert( pList!=0 );
+  for(i=0; i<pList->nExpr; i++){
+    if( sqlite3ResolveExprNames(pNC, pList->a[i].pExpr) ) return WRC_Abort;
+  }
+  return WRC_Continue;
+}
 
 /*
 ** Resolve all names in all expressions of a SELECT and in all
@@ -84127,15 +84958,14 @@ SQLITE_PRIVATE void sqlite3ResolveSelectNames(
 SQLITE_PRIVATE void sqlite3ResolveSelfReference(
   Parse *pParse,      /* Parsing context */
   Table *pTab,        /* The table being referenced */
-  int type,           /* NC_IsCheck or NC_PartIdx */
+  int type,           /* NC_IsCheck or NC_PartIdx or NC_IdxExpr */
   Expr *pExpr,        /* Expression to resolve.  May be NULL. */
   ExprList *pList     /* Expression list to resolve.  May be NUL. */
 ){
   SrcList sSrc;                   /* Fake SrcList for pParse->pNewTable */
   NameContext sNC;                /* Name context for pParse->pNewTable */
-  int i;                          /* Loop counter */
 
-  assert( type==NC_IsCheck || type==NC_PartIdx );
+  assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr );
   memset(&sNC, 0, sizeof(sNC));
   memset(&sSrc, 0, sizeof(sSrc));
   sSrc.nSrc = 1;
@@ -84146,13 +84976,7 @@ SQLITE_PRIVATE void sqlite3ResolveSelfReference(
   sNC.pSrcList = &sSrc;
   sNC.ncFlags = type;
   if( sqlite3ResolveExprNames(&sNC, pExpr) ) return;
-  if( pList ){
-    for(i=0; i<pList->nExpr; i++){
-      if( sqlite3ResolveExprNames(&sNC, pList->a[i].pExpr) ){
-        return;
-      }
-    }
-  }
+  if( pList ) sqlite3ResolveExprListNames(&sNC, pList);
 }
 
 /************** End of resolve.c *********************************************/
@@ -84250,7 +85074,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, con
 }
 
 /*
-** Skip over any TK_COLLATE or TK_AS operators and any unlikely()
+** Skip over any TK_COLLATE operators and any unlikely()
 ** or likelihood() function at the root of an expression.
 */
 SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){
@@ -84261,7 +85085,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){
       assert( pExpr->op==TK_FUNCTION );
       pExpr = pExpr->x.pList->a[0].pExpr;
     }else{
-      assert( pExpr->op==TK_COLLATE || pExpr->op==TK_AS );
+      assert( pExpr->op==TK_COLLATE );
       pExpr = pExpr->pLeft;
     }
   }   
@@ -84592,7 +85416,7 @@ SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
 ** is responsible for making sure the node eventually gets freed.
 **
 ** If dequote is true, then the token (if it exists) is dequoted.
-** If dequote is false, no dequoting is performance.  The deQuote
+** If dequote is false, no dequoting is performed.  The deQuote
 ** parameter is ignored if pToken is NULL or if the token does not
 ** appear to be quoted.  If the quotes were of the form "..." (double-quotes)
 ** then the EP_DblQuoted flag is set on the expression node.
@@ -85193,16 +86017,18 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
     pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase);
     pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
     pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias);
-    pNewItem->jointype = pOldItem->jointype;
+    pNewItem->fg = pOldItem->fg;
     pNewItem->iCursor = pOldItem->iCursor;
     pNewItem->addrFillSub = pOldItem->addrFillSub;
     pNewItem->regReturn = pOldItem->regReturn;
-    pNewItem->isCorrelated = pOldItem->isCorrelated;
-    pNewItem->viaCoroutine = pOldItem->viaCoroutine;
-    pNewItem->isRecursive = pOldItem->isRecursive;
-    pNewItem->zIndexedBy = sqlite3DbStrDup(db, pOldItem->zIndexedBy);
-    pNewItem->notIndexed = pOldItem->notIndexed;
-    pNewItem->pIndex = pOldItem->pIndex;
+    if( pNewItem->fg.isIndexedBy ){
+      pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy);
+    }
+    pNewItem->pIBIndex = pOldItem->pIBIndex;
+    if( pNewItem->fg.isTabFunc ){
+      pNewItem->u1.pFuncArg = 
+          sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, flags);
+    }
     pTab = pNewItem->pTab = pOldItem->pTab;
     if( pTab ){
       pTab->nRef++;
@@ -85317,6 +86143,20 @@ no_mem:
   return 0;
 }
 
+/*
+** Set the sort order for the last element on the given ExprList.
+*/
+SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder){
+  if( p==0 ) return;
+  assert( SQLITE_SO_UNDEFINED<0 && SQLITE_SO_ASC>=0 && SQLITE_SO_DESC>0 );
+  assert( p->nExpr>0 );
+  if( iSortOrder<0 ){
+    assert( p->a[p->nExpr-1].sortOrder==SQLITE_SO_ASC );
+    return;
+  }
+  p->a[p->nExpr-1].sortOrder = (u8)iSortOrder;
+}
+
 /*
 ** Set the ExprList.a[].zName element of the most recently added item
 ** on the expression list.
@@ -85738,13 +86578,13 @@ SQLITE_PRIVATE int sqlite3CodeOnce(Parse *pParse){
 ** to be set to NULL if iCur contains one or more NULL values.
 */
 static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){
-  int j1;
+  int addr1;
   sqlite3VdbeAddOp2(v, OP_Integer, 0, regHasNull);
-  j1 = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v);
+  addr1 = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v);
   sqlite3VdbeAddOp3(v, OP_Column, iCur, 0, regHasNull);
   sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
   VdbeComment((v, "first_entry_in(%d)", iCur));
-  sqlite3VdbeJumpHere(v, j1);
+  sqlite3VdbeJumpHere(v, addr1);
 }
 
 
@@ -86288,7 +87128,7 @@ static void sqlite3ExprCodeIN(
     }
     if( regCkNull ){
       sqlite3VdbeAddOp2(v, OP_IsNull, regCkNull, destIfNull); VdbeCoverage(v);
-      sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse);
+      sqlite3VdbeGoto(v, destIfFalse);
     }
     sqlite3VdbeResolveLabel(v, labelOk);
     sqlite3ReleaseTempReg(pParse, regCkNull);
@@ -86306,7 +87146,7 @@ static void sqlite3ExprCodeIN(
         int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v);
         sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
         VdbeCoverage(v);
-        sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);
+        sqlite3VdbeGoto(v, destIfNull);
         sqlite3VdbeJumpHere(v, addr1);
       }
     }
@@ -86344,7 +87184,7 @@ static void sqlite3ExprCodeIN(
         ** the presence of a NULL on the RHS makes a difference in the
         ** outcome.
         */
-        int j1;
+        int addr1;
   
         /* First check to see if the LHS is contained in the RHS.  If so,
         ** then the answer is TRUE the presence of NULLs in the RHS does
@@ -86352,12 +87192,12 @@ static void sqlite3ExprCodeIN(
         ** answer is NULL if the RHS contains NULLs and the answer is
         ** FALSE if the RHS is NULL-free.
         */
-        j1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1);
+        addr1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1);
         VdbeCoverage(v);
         sqlite3VdbeAddOp2(v, OP_IsNull, rRhsHasNull, destIfNull);
         VdbeCoverage(v);
-        sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse);
-        sqlite3VdbeJumpHere(v, j1);
+        sqlite3VdbeGoto(v, destIfFalse);
+        sqlite3VdbeJumpHere(v, addr1);
       }
     }
   }
@@ -86575,6 +87415,28 @@ static void sqlite3ExprCachePinRegister(Parse *pParse, int iReg){
   }
 }
 
+/* Generate code that will load into register regOut a value that is
+** appropriate for the iIdxCol-th column of index pIdx.
+*/
+SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn(
+  Parse *pParse,  /* The parsing context */
+  Index *pIdx,    /* The index whose column is to be loaded */
+  int iTabCur,    /* Cursor pointing to a table row */
+  int iIdxCol,    /* The column of the index to be loaded */
+  int regOut      /* Store the index column value in this register */
+){
+  i16 iTabCol = pIdx->aiColumn[iIdxCol];
+  if( iTabCol==XN_EXPR ){
+    assert( pIdx->aColExpr );
+    assert( pIdx->aColExpr->nExpr>iIdxCol );
+    pParse->iSelfTab = iTabCur;
+    sqlite3ExprCode(pParse, pIdx->aColExpr->a[iIdxCol].pExpr, regOut);
+  }else{
+    sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable, iTabCur,
+                                    iTabCol, regOut);
+  }
+}
+
 /*
 ** Generate code to extract the value of the iCol-th column of a table.
 */
@@ -86760,8 +87622,9 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
           inReg = pExpr->iColumn + pParse->ckBase;
           break;
         }else{
-          /* Deleting from a partial index */
-          iTab = pParse->iPartIdxTab;
+          /* Coding an expression that is part of an index where column names
+          ** in the index refer to the table to which the index belongs */
+          iTab = pParse->iSelfTab;
         }
       }
       inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
@@ -86782,7 +87645,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
 #endif
     case TK_STRING: {
       assert( !ExprHasProperty(pExpr, EP_IntValue) );
-      sqlite3VdbeAddOp4(v, OP_String8, 0, target, 0, pExpr->u.zToken, 0);
+      sqlite3VdbeLoadString(v, target, pExpr->u.zToken);
       break;
     }
     case TK_NULL: {
@@ -86821,10 +87684,6 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
       inReg = pExpr->iTable;
       break;
     }
-    case TK_AS: {
-      inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
-      break;
-    }
 #ifndef SQLITE_OMIT_CAST
     case TK_CAST: {
       /* Expressions of the form:   CAST(pLeft AS token) */
@@ -87055,7 +87914,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
         }
 
         sqlite3ExprCachePush(pParse);     /* Ticket 2ea2425d34be */
-        sqlite3ExprCodeExprList(pParse, pFarg, r1,
+        sqlite3ExprCodeExprList(pParse, pFarg, r1, 0,
                                 SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR);
         sqlite3ExprCachePop(pParse);      /* Ticket 2ea2425d34be */
       }else{
@@ -87279,7 +88138,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
         sqlite3ExprIfFalse(pParse, pTest, nextCase, SQLITE_JUMPIFNULL);
         testcase( aListelem[i+1].pExpr->op==TK_COLUMN );
         sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target);
-        sqlite3VdbeAddOp2(v, OP_Goto, 0, endLabel);
+        sqlite3VdbeGoto(v, endLabel);
         sqlite3ExprCachePop(pParse);
         sqlite3VdbeResolveLabel(v, nextCase);
       }
@@ -87471,11 +88330,13 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(
   Parse *pParse,     /* Parsing context */
   ExprList *pList,   /* The expression list to be coded */
   int target,        /* Where to write results */
+  int srcReg,        /* Source registers if SQLITE_ECEL_REF */
   u8 flags           /* SQLITE_ECEL_* flags */
 ){
   struct ExprList_item *pItem;
-  int i, n;
+  int i, j, n;
   u8 copyOp = (flags & SQLITE_ECEL_DUP) ? OP_Copy : OP_SCopy;
+  Vdbe *v = pParse->pVdbe;
   assert( pList!=0 );
   assert( target>0 );
   assert( pParse->pVdbe!=0 );  /* Never gets this far otherwise */
@@ -87483,13 +88344,14 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(
   if( !ConstFactorOk(pParse) ) flags &= ~SQLITE_ECEL_FACTOR;
   for(pItem=pList->a, i=0; i<n; i++, pItem++){
     Expr *pExpr = pItem->pExpr;
-    if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){
+    if( (flags & SQLITE_ECEL_REF)!=0 && (j = pList->a[i].u.x.iOrderByCol)>0 ){
+      sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i);
+    }else if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){
       sqlite3ExprCodeAtInit(pParse, pExpr, target+i, 0);
     }else{
       int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
       if( inReg!=target+i ){
         VdbeOp *pOp;
-        Vdbe *v = pParse->pVdbe;
         if( copyOp==OP_Copy
          && (pOp=sqlite3VdbeGetOp(v, -1))->opcode==OP_Copy
          && pOp->p1+pOp->p3+1==inReg
@@ -87666,14 +88528,14 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
       int destIfFalse = sqlite3VdbeMakeLabel(v);
       int destIfNull = jumpIfNull ? dest : destIfFalse;
       sqlite3ExprCodeIN(pParse, pExpr, destIfFalse, destIfNull);
-      sqlite3VdbeAddOp2(v, OP_Goto, 0, dest);
+      sqlite3VdbeGoto(v, dest);
       sqlite3VdbeResolveLabel(v, destIfFalse);
       break;
     }
 #endif
     default: {
       if( exprAlwaysTrue(pExpr) ){
-        sqlite3VdbeAddOp2(v, OP_Goto, 0, dest);
+        sqlite3VdbeGoto(v, dest);
       }else if( exprAlwaysFalse(pExpr) ){
         /* No-op */
       }else{
@@ -87829,7 +88691,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
 #endif
     default: {
       if( exprAlwaysFalse(pExpr) ){
-        sqlite3VdbeAddOp2(v, OP_Goto, 0, dest);
+        sqlite3VdbeGoto(v, dest);
       }else if( exprAlwaysTrue(pExpr) ){
         /* no-op */
       }else{
@@ -87905,7 +88767,9 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){
     return 2;
   }
   if( pA->op!=TK_COLUMN && ALWAYS(pA->op!=TK_AGG_COLUMN) && pA->u.zToken ){
-    if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){
+    if( pA->op==TK_FUNCTION ){
+      if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2;
+    }else if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){
       return pA->op==TK_COLLATE ? 1 : 2;
     }
   }
@@ -88813,7 +89677,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
 #ifndef SQLITE_OMIT_VIRTUALTABLE
   if( pVTab ){
     int i = ++pParse->nMem;
-    sqlite3VdbeAddOp4(v, OP_String8, 0, i, 0, zName, 0);
+    sqlite3VdbeLoadString(v, i, zName);
     sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB);
     sqlite3MayAbort(pParse);
   }
@@ -88924,14 +89788,14 @@ SQLITE_PRIVATE void sqlite3MinimumFileFormat(Parse *pParse, int iDb, int minForm
   if( ALWAYS(v) ){
     int r1 = sqlite3GetTempReg(pParse);
     int r2 = sqlite3GetTempReg(pParse);
-    int j1;
+    int addr1;
     sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT);
     sqlite3VdbeUsesBtree(v, iDb);
     sqlite3VdbeAddOp2(v, OP_Integer, minFormat, r2);
-    j1 = sqlite3VdbeAddOp3(v, OP_Ge, r2, 0, r1);
+    addr1 = sqlite3VdbeAddOp3(v, OP_Ge, r2, 0, r1);
     sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); VdbeCoverage(v);
     sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, r2);
-    sqlite3VdbeJumpHere(v, j1);
+    sqlite3VdbeJumpHere(v, addr1);
     sqlite3ReleaseTempReg(pParse, r1);
     sqlite3ReleaseTempReg(pParse, r2);
   }
@@ -90171,7 +91035,7 @@ static void analyzeOneTable(
   iIdxCur = iTab++;
   pParse->nTab = MAX(pParse->nTab, iTab);
   sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
-  sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0);
+  sqlite3VdbeLoadString(v, regTabname, pTab->zName);
 
   for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
     int nCol;                     /* Number of columns in pIdx. "N" */
@@ -90193,7 +91057,7 @@ static void analyzeOneTable(
     }
 
     /* Populate the register containing the index name. */
-    sqlite3VdbeAddOp4(v, OP_String8, 0, regIdxname, 0, zIdxName, 0);
+    sqlite3VdbeLoadString(v, regIdxname, zIdxName);
     VdbeComment((v, "Analysis for %s.%s", pTab->zName, zIdxName));
 
     /*
@@ -90307,7 +91171,7 @@ static void analyzeOneTable(
         VdbeCoverage(v);
       }
       sqlite3VdbeAddOp2(v, OP_Integer, nColTest, regChng);
-      sqlite3VdbeAddOp2(v, OP_Goto, 0, endDistinctTest);
+      sqlite3VdbeGoto(v, endDistinctTest);
   
   
       /*
@@ -90343,6 +91207,7 @@ static void analyzeOneTable(
       regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
       for(j=0; j<pPk->nKeyCol; j++){
         k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]);
+        assert( k>=0 && k<pTab->nCol );
         sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
         VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName));
       }
@@ -90392,12 +91257,10 @@ static void analyzeOneTable(
       ** be taken */
       VdbeCoverageNeverTaken(v);
 #ifdef SQLITE_ENABLE_STAT3
-      sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, 
-                                      pIdx->aiColumn[0], regSample);
+      sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, 0, regSample);
 #else
       for(i=0; i<nCol; i++){
-        i16 iCol = pIdx->aiColumn[i];
-        sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, iCol, regCol+i);
+        sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, i, regCol+i);
       }
       sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol, regSample);
 #endif
@@ -92094,6 +92957,8 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
           db->aDb[iDb].pSchema->iGeneration  /* P4 */
         );
         if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
+        VdbeComment((v,
+              "usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite));
       }
 #ifndef SQLITE_OMIT_VIRTUALTABLE
       for(i=0; i<pParse->nVtabLock; i++){
@@ -92123,7 +92988,7 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
       }
 
       /* Finally, jump back to the beginning of the executable code. */
-      sqlite3VdbeAddOp2(v, OP_Goto, 0, 1);
+      sqlite3VdbeGoto(v, 1);
     }
   }
 
@@ -92258,6 +93123,17 @@ SQLITE_PRIVATE Table *sqlite3LocateTable(
   p = sqlite3FindTable(pParse->db, zName, zDbase);
   if( p==0 ){
     const char *zMsg = isView ? "no such view" : "no such table";
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+    if( sqlite3FindDbName(pParse->db, zDbase)<1 ){
+      /* If zName is the not the name of a table in the schema created using
+      ** CREATE, then check to see if it is the name of an virtual table that
+      ** can be an eponymous virtual table. */
+      Module *pMod = (Module*)sqlite3HashFind(&pParse->db->aModule, zName);
+      if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){
+        return pMod->pEpoTab;
+      }
+    }
+#endif
     if( zDbase ){
       sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
     }else{
@@ -92265,7 +93141,7 @@ SQLITE_PRIVATE Table *sqlite3LocateTable(
     }
     pParse->checkSchema = 1;
   }
-#if SQLITE_USER_AUTHENICATION
+#if SQLITE_USER_AUTHENTICATION
   else if( pParse->db->auth.authLevel<UAUTH_User ){
     sqlite3ErrorMsg(pParse, "user not authenticated");
     p = 0;
@@ -92336,6 +93212,7 @@ static void freeIndex(sqlite3 *db, Index *p){
   sqlite3DeleteIndexSamples(db, p);
 #endif
   sqlite3ExprDelete(db, p->pPartIdxWhere);
+  sqlite3ExprListDelete(db, p->aColExpr);
   sqlite3DbFree(db, p->zColAff);
   if( p->isResized ) sqlite3DbFree(db, p->azColl);
 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
@@ -92462,7 +93339,7 @@ SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3 *db){
 ** Delete memory allocated for the column names of a table or view (the
 ** Table.aCol[] array).
 */
-static void sqliteDeleteColumnNames(sqlite3 *db, Table *pTable){
+SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
   int i;
   Column *pCol;
   assert( pTable!=0 );
@@ -92529,13 +93406,11 @@ SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
 
   /* Delete the Table structure itself.
   */
-  sqliteDeleteColumnNames(db, pTable);
+  sqlite3DeleteColumnNames(db, pTable);
   sqlite3DbFree(db, pTable->zName);
   sqlite3DbFree(db, pTable->zColAff);
   sqlite3SelectDelete(db, pTable->pSelect);
-#ifndef SQLITE_OMIT_CHECK
   sqlite3ExprListDelete(db, pTable->pCheck);
-#endif
 #ifndef SQLITE_OMIT_VIRTUALTABLE
   sqlite3VtabClear(db, pTable);
 #endif
@@ -92875,9 +93750,11 @@ SQLITE_PRIVATE void sqlite3StartTable(
   ** now.
   */
   if( !db->init.busy && (v = sqlite3GetVdbe(pParse))!=0 ){
-    int j1;
+    int addr1;
     int fileFormat;
     int reg1, reg2, reg3;
+    /* nullRow[] is an OP_Record encoding of a row containing 5 NULLs */
+    static const char nullRow[] = { 6, 0, 0, 0, 0, 0 };
     sqlite3BeginWriteOperation(pParse, 1, iDb);
 
 #ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -92894,14 +93771,14 @@ SQLITE_PRIVATE void sqlite3StartTable(
     reg3 = ++pParse->nMem;
     sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, reg3, BTREE_FILE_FORMAT);
     sqlite3VdbeUsesBtree(v, iDb);
-    j1 = sqlite3VdbeAddOp1(v, OP_If, reg3); VdbeCoverage(v);
+    addr1 = sqlite3VdbeAddOp1(v, OP_If, reg3); VdbeCoverage(v);
     fileFormat = (db->flags & SQLITE_LegacyFileFmt)!=0 ?
                   1 : SQLITE_MAX_FILE_FORMAT;
     sqlite3VdbeAddOp2(v, OP_Integer, fileFormat, reg3);
     sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, reg3);
     sqlite3VdbeAddOp2(v, OP_Integer, ENC(db), reg3);
     sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, reg3);
-    sqlite3VdbeJumpHere(v, j1);
+    sqlite3VdbeJumpHere(v, addr1);
 
     /* This just creates a place-holder record in the sqlite_master table.
     ** The record created does not contain anything yet.  It will be replaced
@@ -92922,7 +93799,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
     }
     sqlite3OpenMasterTable(pParse, iDb);
     sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1);
-    sqlite3VdbeAddOp2(v, OP_Null, 0, reg3);
+    sqlite3VdbeAddOp4(v, OP_Blob, 6, reg3, 0, nullRow, P4_STATIC);
     sqlite3VdbeAddOp3(v, OP_Insert, 0, reg3, reg1);
     sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
     sqlite3VdbeAddOp0(v, OP_Close);
@@ -93203,18 +94080,23 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
   }else{
     nTerm = pList->nExpr;
     for(i=0; i<nTerm; i++){
-      for(iCol=0; iCol<pTab->nCol; iCol++){
-        if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[iCol].zName)==0 ){
-          pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
-          zType = pTab->aCol[iCol].zType;
-          break;
+      Expr *pCExpr = sqlite3ExprSkipCollate(pList->a[i].pExpr);
+      assert( pCExpr!=0 );
+      if( pCExpr->op==TK_ID ){
+        const char *zCName = pCExpr->u.zToken;
+        for(iCol=0; iCol<pTab->nCol; iCol++){
+          if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){
+            pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
+            zType = pTab->aCol[iCol].zType;
+            break;
+          }
         }
       }
     }
   }
   if( nTerm==1
    && zType && sqlite3StrICmp(zType, "INTEGER")==0
-   && sortOrder==SQLITE_SO_ASC
+   && sortOrder!=SQLITE_SO_DESC
   ){
     pTab->iPKey = iCol;
     pTab->keyConf = (u8)onError;
@@ -93581,7 +94463,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
   */
   if( pParse->addrCrTab ){
     assert( v );
-    sqlite3VdbeGetOp(v, pParse->addrCrTab)->opcode = OP_CreateIndex;
+    sqlite3VdbeChangeOpcode(v, pParse->addrCrTab, OP_CreateIndex);
   }
 
   /* Locate the PRIMARY KEY index.  Or, if this table was originally
@@ -93589,10 +94471,12 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
   */
   if( pTab->iPKey>=0 ){
     ExprList *pList;
-    pList = sqlite3ExprListAppend(pParse, 0, 0);
+    Token ipkToken;
+    ipkToken.z = pTab->aCol[pTab->iPKey].zName;
+    ipkToken.n = sqlite3Strlen30(ipkToken.z);
+    pList = sqlite3ExprListAppend(pParse, 0, 
+                  sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0));
     if( pList==0 ) return;
-    pList->a[0].zName = sqlite3DbStrDup(pParse->db,
-                                        pTab->aCol[pTab->iPKey].zName);
     pList->a[0].sortOrder = pParse->iPkSortOrder;
     assert( pParse->pNewTable==pTab );
     pPk = sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0);
@@ -93608,7 +94492,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
     ** a database schema).  */
     if( v ){
       assert( db->init.busy==0 );
-      sqlite3VdbeGetOp(v, pPk->tnum)->opcode = OP_Goto;
+      sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto);
     }
 
     /*
@@ -93718,9 +94602,10 @@ SQLITE_PRIVATE void sqlite3EndTable(
   int iDb;                  /* Database in which the table lives */
   Index *pIdx;              /* An implied index of the table */
 
-  if( (pEnd==0 && pSelect==0) || db->mallocFailed ){
+  if( pEnd==0 && pSelect==0 ){
     return;
   }
+  assert( !db->mallocFailed );
   p = pParse->pNewTable;
   if( p==0 ) return;
 
@@ -93851,7 +94736,7 @@ SQLITE_PRIVATE void sqlite3EndTable(
       sqlite3TableAffinity(v, p, 0);
       sqlite3VdbeAddOp2(v, OP_NewRowid, 1, regRowid);
       sqlite3VdbeAddOp3(v, OP_Insert, 1, regRec, regRowid);
-      sqlite3VdbeAddOp2(v, OP_Goto, 0, addrInsLoop);
+      sqlite3VdbeGoto(v, addrInsLoop);
       sqlite3VdbeJumpHere(v, addrInsLoop);
       sqlite3VdbeAddOp1(v, OP_Close, 1);
     }
@@ -93948,6 +94833,7 @@ SQLITE_PRIVATE void sqlite3CreateView(
   Token *pBegin,     /* The CREATE token that begins the statement */
   Token *pName1,     /* The token that holds the name of the view */
   Token *pName2,     /* The token that holds the name of the view */
+  ExprList *pCNames, /* Optional list of view column names */
   Select *pSelect,   /* A SELECT statement that will become the new view */
   int isTemp,        /* TRUE for a TEMPORARY view */
   int noErr          /* Suppress error messages if VIEW already exists */
@@ -93963,22 +94849,15 @@ SQLITE_PRIVATE void sqlite3CreateView(
 
   if( pParse->nVar>0 ){
     sqlite3ErrorMsg(pParse, "parameters are not allowed in views");
-    sqlite3SelectDelete(db, pSelect);
-    return;
+    goto create_view_fail;
   }
   sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr);
   p = pParse->pNewTable;
-  if( p==0 || pParse->nErr ){
-    sqlite3SelectDelete(db, pSelect);
-    return;
-  }
+  if( p==0 || pParse->nErr ) goto create_view_fail;
   sqlite3TwoPartName(pParse, pName1, pName2, &pName);
   iDb = sqlite3SchemaToIndex(db, p->pSchema);
   sqlite3FixInit(&sFix, pParse, iDb, "view", pName);
-  if( sqlite3FixSelect(&sFix, pSelect) ){
-    sqlite3SelectDelete(db, pSelect);
-    return;
-  }
+  if( sqlite3FixSelect(&sFix, pSelect) ) goto create_view_fail;
 
   /* Make a copy of the entire SELECT statement that defines the view.
   ** This will force all the Expr.token.z values to be dynamically
@@ -93986,30 +94865,31 @@ SQLITE_PRIVATE void sqlite3CreateView(
   ** they will persist after the current sqlite3_exec() call returns.
   */
   p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
-  sqlite3SelectDelete(db, pSelect);
-  if( db->mallocFailed ){
-    return;
-  }
-  if( !db->init.busy ){
-    sqlite3ViewGetColumnNames(pParse, p);
-  }
+  p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE);
+  if( db->mallocFailed ) goto create_view_fail;
 
   /* Locate the end of the CREATE VIEW statement.  Make sEnd point to
   ** the end.
   */
   sEnd = pParse->sLastToken;
-  if( ALWAYS(sEnd.z[0]!=0) && sEnd.z[0]!=';' ){
+  assert( sEnd.z[0]!=0 );
+  if( sEnd.z[0]!=';' ){
     sEnd.z += sEnd.n;
   }
   sEnd.n = 0;
   n = (int)(sEnd.z - pBegin->z);
+  assert( n>0 );
   z = pBegin->z;
-  while( ALWAYS(n>0) && sqlite3Isspace(z[n-1]) ){ n--; }
+  while( sqlite3Isspace(z[n-1]) ){ n--; }
   sEnd.z = &z[n-1];
   sEnd.n = 1;
 
   /* Use sqlite3EndTable() to add the view to the SQLITE_MASTER table */
   sqlite3EndTable(pParse, 0, &sEnd, 0, 0);
+
+create_view_fail:
+  sqlite3SelectDelete(db, pSelect);
+  sqlite3ExprListDelete(db, pCNames);
   return;
 }
 #endif /* SQLITE_OMIT_VIEW */
@@ -94027,6 +94907,7 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
   int n;            /* Temporarily holds the number of cursors assigned */
   sqlite3 *db = pParse->db;  /* Database connection for malloc errors */
   sqlite3_xauth xAuth;       /* Saved xAuth pointer */
+  u8 bEnabledLA;             /* Saved db->lookaside.bEnabled state */
 
   assert( pTable );
 
@@ -94072,40 +94953,46 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
   ** statement that defines the view.
   */
   assert( pTable->pSelect );
-  pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
-  if( pSel ){
-    u8 enableLookaside = db->lookaside.bEnabled;
-    n = pParse->nTab;
-    sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
-    pTable->nCol = -1;
+  bEnabledLA = db->lookaside.bEnabled;
+  if( pTable->pCheck ){
     db->lookaside.bEnabled = 0;
+    sqlite3ColumnsFromExprList(pParse, pTable->pCheck, 
+                               &pTable->nCol, &pTable->aCol);
+  }else{
+    pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
+    if( pSel ){
+      n = pParse->nTab;
+      sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
+      pTable->nCol = -1;
+      db->lookaside.bEnabled = 0;
 #ifndef SQLITE_OMIT_AUTHORIZATION
-    xAuth = db->xAuth;
-    db->xAuth = 0;
-    pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
-    db->xAuth = xAuth;
+      xAuth = db->xAuth;
+      db->xAuth = 0;
+      pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
+      db->xAuth = xAuth;
 #else
-    pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
-#endif
-    db->lookaside.bEnabled = enableLookaside;
-    pParse->nTab = n;
-    if( pSelTab ){
-      assert( pTable->aCol==0 );
-      pTable->nCol = pSelTab->nCol;
-      pTable->aCol = pSelTab->aCol;
-      pSelTab->nCol = 0;
-      pSelTab->aCol = 0;
-      sqlite3DeleteTable(db, pSelTab);
-      assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
-      pTable->pSchema->schemaFlags |= DB_UnresetViews;
-    }else{
-      pTable->nCol = 0;
+      pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
+#endif
+      pParse->nTab = n;
+      if( pSelTab ){
+        assert( pTable->aCol==0 );
+        pTable->nCol = pSelTab->nCol;
+        pTable->aCol = pSelTab->aCol;
+        pSelTab->nCol = 0;
+        pSelTab->aCol = 0;
+        sqlite3DeleteTable(db, pSelTab);
+        assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
+      }else{
+        pTable->nCol = 0;
+        nErr++;
+      }
+      sqlite3SelectDelete(db, pSel);
+    } else {
       nErr++;
     }
-    sqlite3SelectDelete(db, pSel);
-  } else {
-    nErr++;
   }
+  db->lookaside.bEnabled = bEnabledLA;
+  pTable->pSchema->schemaFlags |= DB_UnresetViews;
 #endif /* SQLITE_OMIT_VIEW */
   return nErr;  
 }
@@ -94122,7 +95009,7 @@ static void sqliteViewResetAll(sqlite3 *db, int idx){
   for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){
     Table *pTab = sqliteHashData(i);
     if( pTab->pSelect ){
-      sqliteDeleteColumnNames(db, pTab);
+      sqlite3DeleteColumnNames(db, pTab);
       pTab->aCol = 0;
       pTab->nCol = 0;
     }
@@ -94677,7 +95564,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
   assert( pKey!=0 || db->mallocFailed || pParse->nErr );
   if( IsUniqueIndex(pIndex) && pKey!=0 ){
     int j2 = sqlite3VdbeCurrentAddr(v) + 3;
-    sqlite3VdbeAddOp2(v, OP_Goto, 0, j2);
+    sqlite3VdbeGoto(v, j2);
     addr2 = sqlite3VdbeCurrentAddr(v);
     sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord,
                          pIndex->nKeyCol); VdbeCoverage(v);
@@ -94733,6 +95620,30 @@ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(
   return p;
 }
 
+/*
+** Backwards Compatibility Hack:
+** 
+** Historical versions of SQLite accepted strings as column names in
+** indexes and PRIMARY KEY constraints and in UNIQUE constraints.  Example:
+**
+**     CREATE TABLE xyz(a,b,c,d,e,PRIMARY KEY('a'),UNIQUE('b','c' COLLATE trim)
+**     CREATE INDEX abc ON xyz('c','d' DESC,'e' COLLATE nocase DESC);
+**
+** This is goofy.  But to preserve backwards compatibility we continue to
+** accept it.  This routine does the necessary conversion.  It converts
+** the expression given in its argument from a TK_STRING into a TK_ID
+** if the expression is just a TK_STRING with an optional COLLATE clause.
+** If the epxression is anything other than TK_STRING, the expression is
+** unchanged.
+*/
+static void sqlite3StringToId(Expr *p){
+  if( p->op==TK_STRING ){
+    p->op = TK_ID;
+  }else if( p->op==TK_COLLATE && p->pLeft->op==TK_STRING ){
+    p->pLeft->op = TK_ID;
+  }
+}
+
 /*
 ** Create a new index for an SQL table.  pName1.pName2 is the name of the index 
 ** and pTblList is the name of the table that is to be indexed.  Both will 
@@ -94774,7 +95685,6 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
   int iDb;             /* Index of the database that is being written */
   Token *pName = 0;    /* Unqualified name of the index to create */
   struct ExprList_item *pListItem; /* For looping over pList */
-  const Column *pTabCol;           /* A column in the table */
   int nExtra = 0;                  /* Space allocated for zExtra[] */
   int nExtraCol;                   /* Number of extra columns needed */
   char *zExtra = 0;                /* Extra space after the Index object */
@@ -94929,11 +95839,16 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
   ** So create a fake list to simulate this.
   */
   if( pList==0 ){
-    pList = sqlite3ExprListAppend(pParse, 0, 0);
+    Token prevCol;
+    prevCol.z = pTab->aCol[pTab->nCol-1].zName;
+    prevCol.n = sqlite3Strlen30(prevCol.z);
+    pList = sqlite3ExprListAppend(pParse, 0,
+              sqlite3ExprAlloc(db, TK_ID, &prevCol, 0));
     if( pList==0 ) goto exit_create_index;
-    pList->a[0].zName = sqlite3DbStrDup(pParse->db,
-                                        pTab->aCol[pTab->nCol-1].zName);
-    pList->a[0].sortOrder = (u8)sortOrder;
+    assert( pList->nExpr==1 );
+    sqlite3ExprListSetSortOrder(pList, sortOrder);
+  }else{
+    sqlite3ExprListCheckLength(pParse, pList, "index");
   }
 
   /* Figure out how many bytes of space are required to store explicitly
@@ -94941,8 +95856,8 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
   */
   for(i=0; i<pList->nExpr; i++){
     Expr *pExpr = pList->a[i].pExpr;
-    if( pExpr ){
-      assert( pExpr->op==TK_COLLATE );
+    assert( pExpr!=0 );
+    if( pExpr->op==TK_COLLATE ){
       nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken));
     }
   }
@@ -94983,35 +95898,54 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
     sortOrderMask = 0;    /* Ignore DESC */
   }
 
-  /* Scan the names of the columns of the table to be indexed and
-  ** load the column indices into the Index structure.  Report an error
-  ** if any column is not found.
+  /* Analyze the list of expressions that form the terms of the index and
+  ** report any errors.  In the common case where the expression is exactly
+  ** a table column, store that column in aiColumn[].  For general expressions,
+  ** populate pIndex->aColExpr and store XN_EXPR (-2) in aiColumn[].
   **
-  ** TODO:  Add a test to make sure that the same column is not named
-  ** more than once within the same index.  Only the first instance of
-  ** the column will ever be used by the optimizer.  Note that using the
-  ** same column more than once cannot be an error because that would 
-  ** break backwards compatibility - it needs to be a warning.
+  ** TODO: Issue a warning if two or more columns of the index are identical.
+  ** TODO: Issue a warning if the table primary key is used as part of the
+  ** index key.
   */
   for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){
-    const char *zColName = pListItem->zName;
-    int requestedSortOrder;
+    Expr *pCExpr;                  /* The i-th index expression */
+    int requestedSortOrder;        /* ASC or DESC on the i-th expression */
     char *zColl;                   /* Collation sequence name */
 
-    for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){
-      if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break;
-    }
-    if( j>=pTab->nCol ){
-      sqlite3ErrorMsg(pParse, "table %s has no column named %s",
-        pTab->zName, zColName);
-      pParse->checkSchema = 1;
-      goto exit_create_index;
+    sqlite3StringToId(pListItem->pExpr);
+    sqlite3ResolveSelfReference(pParse, pTab, NC_IdxExpr, pListItem->pExpr, 0);
+    if( pParse->nErr ) goto exit_create_index;
+    pCExpr = sqlite3ExprSkipCollate(pListItem->pExpr);
+    if( pCExpr->op!=TK_COLUMN ){
+      if( pTab==pParse->pNewTable ){
+        sqlite3ErrorMsg(pParse, "expressions prohibited in PRIMARY KEY and "
+                                "UNIQUE constraints");
+        goto exit_create_index;
+      }
+      if( pIndex->aColExpr==0 ){
+        ExprList *pCopy = sqlite3ExprListDup(db, pList, 0);
+        pIndex->aColExpr = pCopy;
+        if( !db->mallocFailed ){
+          assert( pCopy!=0 );
+          pListItem = &pCopy->a[i];
+        }
+      }
+      j = XN_EXPR;
+      pIndex->aiColumn[i] = XN_EXPR;
+      pIndex->uniqNotNull = 0;
+    }else{
+      j = pCExpr->iColumn;
+      assert( j<=0x7fff );
+      if( j<0 ){
+        j = pTab->iPKey;
+      }else if( pTab->aCol[j].notNull==0 ){
+        pIndex->uniqNotNull = 0;
+      }
+      pIndex->aiColumn[i] = (i16)j;
     }
-    assert( j<=0x7fff );
-    pIndex->aiColumn[i] = (i16)j;
-    if( pListItem->pExpr ){
+    zColl = 0;
+    if( pListItem->pExpr->op==TK_COLLATE ){
       int nColl;
-      assert( pListItem->pExpr->op==TK_COLLATE );
       zColl = pListItem->pExpr->u.zToken;
       nColl = sqlite3Strlen30(zColl) + 1;
       assert( nExtra>=nColl );
@@ -95019,21 +95953,26 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
       zColl = zExtra;
       zExtra += nColl;
       nExtra -= nColl;
-    }else{
+    }else if( j>=0 ){
       zColl = pTab->aCol[j].zColl;
-      if( !zColl ) zColl = "BINARY";
     }
+    if( !zColl ) zColl = "BINARY";
     if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){
       goto exit_create_index;
     }
     pIndex->azColl[i] = zColl;
     requestedSortOrder = pListItem->sortOrder & sortOrderMask;
     pIndex->aSortOrder[i] = (u8)requestedSortOrder;
-    if( pTab->aCol[j].notNull==0 ) pIndex->uniqNotNull = 0;
   }
+
+  /* Append the table key to the end of the index.  For WITHOUT ROWID
+  ** tables (when pPk!=0) this will be the declared PRIMARY KEY.  For
+  ** normal tables (when pPk==0) this will be the rowid.
+  */
   if( pPk ){
     for(j=0; j<pPk->nKeyCol; j++){
       int x = pPk->aiColumn[j];
+      assert( x>=0 );
       if( hasColumn(pIndex->aiColumn, pIndex->nKeyCol, x) ){
         pIndex->nColumn--; 
       }else{
@@ -95045,7 +95984,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
     }
     assert( i==pIndex->nColumn );
   }else{
-    pIndex->aiColumn[i] = -1;
+    pIndex->aiColumn[i] = XN_ROWID;
     pIndex->azColl[i] = "BINARY";
   }
   sqlite3DefaultRowEst(pIndex);
@@ -95084,6 +96023,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
       for(k=0; k<pIdx->nKeyCol; k++){
         const char *z1;
         const char *z2;
+        assert( pIdx->aiColumn[k]>=0 );
         if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break;
         z1 = pIdx->azColl[k];
         z2 = pIndex->azColl[k];
@@ -95115,6 +96055,7 @@ SQLITE_PRIVATE Index *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( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
@@ -95144,7 +96085,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
   ** has just been created, it contains no data and the index initialization
   ** step can be skipped.
   */
-  else if( pParse->nErr==0 && (HasRowid(pTab) || pTblName!=0) ){
+  else if( HasRowid(pTab) || pTblName!=0 ){
     Vdbe *v;
     char *zStmt;
     int iMem = ++pParse->nMem;
@@ -95604,7 +96545,8 @@ SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
     sqlite3DbFree(db, pItem->zDatabase);
     sqlite3DbFree(db, pItem->zName);
     sqlite3DbFree(db, pItem->zAlias);
-    sqlite3DbFree(db, pItem->zIndexedBy);
+    if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy);
+    if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg);
     sqlite3DeleteTable(db, pItem->pTab);
     sqlite3SelectDelete(db, pItem->pSelect);
     sqlite3ExprDelete(db, pItem->pOn);
@@ -95677,17 +96619,37 @@ SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pI
   assert( pIndexedBy!=0 );
   if( p && ALWAYS(p->nSrc>0) ){
     struct SrcList_item *pItem = &p->a[p->nSrc-1];
-    assert( pItem->notIndexed==0 && pItem->zIndexedBy==0 );
+    assert( pItem->fg.notIndexed==0 );
+    assert( pItem->fg.isIndexedBy==0 );
+    assert( pItem->fg.isTabFunc==0 );
     if( pIndexedBy->n==1 && !pIndexedBy->z ){
       /* A "NOT INDEXED" clause was supplied. See parse.y 
       ** construct "indexed_opt" for details. */
-      pItem->notIndexed = 1;
+      pItem->fg.notIndexed = 1;
     }else{
-      pItem->zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy);
+      pItem->u1.zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy);
+      pItem->fg.isIndexedBy = (pItem->u1.zIndexedBy!=0);
     }
   }
 }
 
+/*
+** Add the list of function arguments to the SrcList entry for a
+** table-valued-function.
+*/
+SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse *pParse, SrcList *p, ExprList *pList){
+  if( p && pList ){
+    struct SrcList_item *pItem = &p->a[p->nSrc-1];
+    assert( pItem->fg.notIndexed==0 );
+    assert( pItem->fg.isIndexedBy==0 );
+    assert( pItem->fg.isTabFunc==0 );
+    pItem->u1.pFuncArg = pList;
+    pItem->fg.isTabFunc = 1;
+  }else{
+    sqlite3ExprListDelete(pParse->db, pList);
+  }
+}
+
 /*
 ** When building up a FROM clause in the parser, the join operator
 ** is initially attached to the left operand.  But the code generator
@@ -95707,9 +96669,9 @@ SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(SrcList *p){
   if( p ){
     int i;
     for(i=p->nSrc-1; i>0; i--){
-      p->a[i].jointype = p->a[i-1].jointype;
+      p->a[i].fg.jointype = p->a[i-1].fg.jointype;
     }
-    p->a[0].jointype = 0;
+    p->a[0].fg.jointype = 0;
   }
 }
 
@@ -95953,12 +96915,16 @@ SQLITE_PRIVATE void sqlite3UniqueConstraint(
   Table *pTab = pIdx->pTable;
 
   sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200);
-  for(j=0; j<pIdx->nKeyCol; j++){
-    char *zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
-    if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2);
-    sqlite3StrAccumAppendAll(&errMsg, pTab->zName);
-    sqlite3StrAccumAppend(&errMsg, ".", 1);
-    sqlite3StrAccumAppendAll(&errMsg, zCol);
+  if( pIdx->aColExpr ){
+    sqlite3XPrintf(&errMsg, 0, "index '%q'", pIdx->zName);
+  }else{
+    for(j=0; j<pIdx->nKeyCol; j++){
+      char *zCol;
+      assert( pIdx->aiColumn[j]>=0 );
+      zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
+      if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2);
+      sqlite3XPrintf(&errMsg, 0, "%s.%s", pTab->zName, zCol);
+    }
   }
   zErr = sqlite3StrAccumFinish(&errMsg);
   sqlite3HaltConstraint(pParse, 
@@ -96203,7 +97169,7 @@ SQLITE_PRIVATE With *sqlite3WithAdd(
     pNew->a[pNew->nCte].pSelect = pQuery;
     pNew->a[pNew->nCte].pCols = pArglist;
     pNew->a[pNew->nCte].zName = zName;
-    pNew->a[pNew->nCte].zErr = 0;
+    pNew->a[pNew->nCte].zCteErr = 0;
     pNew->nCte++;
   }
 
@@ -96946,7 +97912,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
   int iDb;               /* Database number */
   int memCnt = -1;       /* Memory cell used for change counting */
   int rcauth;            /* Value returned by authorization callback */
-  int okOnePass;         /* True for one-pass algorithm without the FIFO */
+  int eOnePass;          /* ONEPASS_OFF or _SINGLE or _MULTI */
   int aiCurOnePass[2];   /* The write cursors opened by WHERE_ONEPASS */
   u8 *aToOpen = 0;       /* Open cursor iTabCur+j if aToOpen[j] is true */
   Index *pPk;            /* The PRIMARY KEY index on the table */
@@ -96958,12 +97924,12 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
   int iRowSet = 0;       /* Register for rowset of rows to delete */
   int addrBypass = 0;    /* Address of jump over the delete logic */
   int addrLoop = 0;      /* Top of the delete loop */
-  int addrDelete = 0;    /* Jump directly to the delete logic */
   int addrEphOpen = 0;   /* Instruction to open the Ephemeral table */
  
 #ifndef SQLITE_OMIT_TRIGGER
   int isView;                  /* True if attempting to delete from a view */
   Trigger *pTrigger;           /* List of table triggers, if required */
+  int bComplex;                /* True if there are either triggers or FKs */
 #endif
 
   memset(&sContext, 0, sizeof(sContext));
@@ -96987,9 +97953,11 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
 #ifndef SQLITE_OMIT_TRIGGER
   pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
   isView = pTab->pSelect!=0;
+  bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0);
 #else
 # define pTrigger 0
 # define isView 0
+# define bComplex 0
 #endif
 #ifdef SQLITE_OMIT_VIEW
 # undef isView
@@ -97070,8 +98038,10 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
   ** It is easier just to erase the whole table. Prior to version 3.6.5,
   ** this optimization caused the row change count (the value returned by 
   ** API function sqlite3_count_changes) to be set incorrectly.  */
-  if( rcauth==SQLITE_OK && pWhere==0 && !pTrigger && !IsVirtual(pTab) 
-   && 0==sqlite3FkRequired(pParse, pTab, 0, 0)
+  if( rcauth==SQLITE_OK
+   && pWhere==0
+   && !bComplex
+   && !IsVirtual(pTab)
   ){
     assert( !isView );
     sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
@@ -97086,6 +98056,8 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
   }else
 #endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
   {
+    u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK;
+    wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW);
     if( HasRowid(pTab) ){
       /* For a rowid table, initialize the RowSet to an empty set */
       pPk = 0;
@@ -97106,13 +98078,18 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
     }
   
     /* Construct a query to find the rowid or primary key for every row
-    ** to be deleted, based on the WHERE clause.
+    ** to be deleted, based on the WHERE clause. Set variable eOnePass
+    ** to indicate the strategy used to implement this delete:
+    **
+    **  ONEPASS_OFF:    Two-pass approach - use a FIFO for rowids/PK values.
+    **  ONEPASS_SINGLE: One-pass approach - at most one row deleted.
+    **  ONEPASS_MULTI:  One-pass approach - any number of rows may be deleted.
     */
-    pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, 
-                               WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK,
-                               iTabCur+1);
+    pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, wcf, iTabCur+1);
     if( pWInfo==0 ) goto delete_from_cleanup;
-    okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
+    eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
+    assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI );
+    assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF );
   
     /* Keep track of the number of rows to be deleted */
     if( db->flags & SQLITE_CountRows ){
@@ -97122,6 +98099,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
     /* Extract the rowid or primary key for the current row */
     if( pPk ){
       for(i=0; i<nPk; i++){
+        assert( pPk->aiColumn[i]>=0 );
         sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur,
                                         pPk->aiColumn[i], iPk+i);
       }
@@ -97132,11 +98110,10 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
       if( iKey>pParse->nMem ) pParse->nMem = iKey;
     }
   
-    if( okOnePass ){
-      /* For ONEPASS, no need to store the rowid/primary-key.  There is only
+    if( eOnePass!=ONEPASS_OFF ){
+      /* For ONEPASS, no need to store the rowid/primary-key. There is only
       ** one, so just keep it in its register(s) and fall through to the
-      ** delete code.
-      */
+      ** delete code.  */
       nKey = nPk; /* OP_Found will use an unpacked key */
       aToOpen = sqlite3DbMallocRaw(db, nIdx+2);
       if( aToOpen==0 ){
@@ -97148,27 +98125,27 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
       if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iTabCur] = 0;
       if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iTabCur] = 0;
       if( addrEphOpen ) sqlite3VdbeChangeToNoop(v, addrEphOpen);
-      addrDelete = sqlite3VdbeAddOp0(v, OP_Goto); /* Jump to DELETE logic */
-    }else if( pPk ){
-      /* Construct a composite key for the row to be deleted and remember it */
-      iKey = ++pParse->nMem;
-      nKey = 0;   /* Zero tells OP_Found to use a composite key */
-      sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey,
-                        sqlite3IndexAffinityStr(v, pPk), nPk);
-      sqlite3VdbeAddOp2(v, OP_IdxInsert, iEphCur, iKey);
     }else{
-      /* Get the rowid of the row to be deleted and remember it in the RowSet */
-      nKey = 1;  /* OP_Seek always uses a single rowid */
-      sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey);
+      if( pPk ){
+        /* Add the PK key for this row to the temporary table */
+        iKey = ++pParse->nMem;
+        nKey = 0;   /* Zero tells OP_Found to use a composite key */
+        sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey,
+            sqlite3IndexAffinityStr(pParse->db, pPk), nPk);
+        sqlite3VdbeAddOp2(v, OP_IdxInsert, iEphCur, iKey);
+      }else{
+        /* Add the rowid of the row to be deleted to the RowSet */
+        nKey = 1;  /* OP_Seek always uses a single rowid */
+        sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey);
+      }
     }
   
-    /* End of the WHERE loop */
-    sqlite3WhereEnd(pWInfo);
-    if( okOnePass ){
-      /* Bypass the delete logic below if the WHERE loop found zero rows */
+    /* If this DELETE cannot use the ONEPASS strategy, this is the 
+    ** end of the WHERE loop */
+    if( eOnePass!=ONEPASS_OFF ){
       addrBypass = sqlite3VdbeMakeLabel(v);
-      sqlite3VdbeAddOp2(v, OP_Goto, 0, addrBypass);
-      sqlite3VdbeJumpHere(v, addrDelete);
+    }else{
+      sqlite3WhereEnd(pWInfo);
     }
   
     /* Unless this is a view, open cursors for the table we are 
@@ -97177,21 +98154,24 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
     ** triggers.
     */
     if( !isView ){
+      int iAddrOnce = 0;
+      if( eOnePass==ONEPASS_MULTI ){
+        iAddrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
+      }
       testcase( IsVirtual(pTab) );
       sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, iTabCur, aToOpen,
                                  &iDataCur, &iIdxCur);
       assert( pPk || IsVirtual(pTab) || iDataCur==iTabCur );
       assert( pPk || IsVirtual(pTab) || iIdxCur==iDataCur+1 );
+      if( eOnePass==ONEPASS_MULTI ) sqlite3VdbeJumpHere(v, iAddrOnce);
     }
   
     /* Set up a loop over the rowids/primary-keys that were found in the
     ** where-clause loop above.
     */
-    if( okOnePass ){
-      /* Just one row.  Hence the top-of-loop is a no-op */
+    if( eOnePass!=ONEPASS_OFF ){
       assert( nKey==nPk );  /* OP_Found will use an unpacked key */
-      assert( !IsVirtual(pTab) );
-      if( aToOpen[iDataCur-iTabCur] ){
+      if( !IsVirtual(pTab) && aToOpen[iDataCur-iTabCur] ){
         assert( pPk!=0 || pTab->pSelect!=0 );
         sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey);
         VdbeCoverage(v);
@@ -97213,23 +98193,32 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
       sqlite3VtabMakeWritable(pParse, pTab);
       sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB);
       sqlite3VdbeChangeP5(v, OE_Abort);
+      assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE );
       sqlite3MayAbort(pParse);
+      if( eOnePass==ONEPASS_SINGLE && sqlite3IsToplevel(pParse) ){
+        pParse->isMultiWrite = 0;
+      }
     }else
 #endif
     {
       int count = (pParse->nested==0);    /* True to count changes */
+      int iIdxNoSeek = -1;
+      if( bComplex==0 && aiCurOnePass[1]!=iDataCur ){
+        iIdxNoSeek = aiCurOnePass[1];
+      }
       sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
-                               iKey, nKey, count, OE_Default, okOnePass);
+          iKey, nKey, count, OE_Default, eOnePass, iIdxNoSeek);
     }
   
     /* End of the loop over all rowids/primary-keys. */
-    if( okOnePass ){
+    if( eOnePass!=ONEPASS_OFF ){
       sqlite3VdbeResolveLabel(v, addrBypass);
+      sqlite3WhereEnd(pWInfo);
     }else if( pPk ){
       sqlite3VdbeAddOp2(v, OP_Next, iEphCur, addrLoop+1); VdbeCoverage(v);
       sqlite3VdbeJumpHere(v, addrLoop);
     }else{
-      sqlite3VdbeAddOp2(v, OP_Goto, 0, addrLoop);
+      sqlite3VdbeGoto(v, addrLoop);
       sqlite3VdbeJumpHere(v, addrLoop);
     }     
   
@@ -97296,6 +98285,25 @@ delete_from_cleanup:
 **       sequence of nPk memory cells starting at iPk.  If nPk==0 that means
 **       that a search record formed from OP_MakeRecord is contained in the
 **       single memory location iPk.
+**
+** eMode:
+**   Parameter eMode may be passed either ONEPASS_OFF (0), ONEPASS_SINGLE, or
+**   ONEPASS_MULTI.  If eMode is not ONEPASS_OFF, then the cursor
+**   iDataCur already points to the row to delete. If eMode is ONEPASS_OFF
+**   then this function must seek iDataCur to the entry identified by iPk
+**   and nPk before reading from it.
+**
+**   If eMode is ONEPASS_MULTI, then this call is being made as part
+**   of a ONEPASS delete that affects multiple rows. In this case, if 
+**   iIdxNoSeek is a valid cursor number (>=0), then its position should
+**   be preserved following the delete operation. Or, if iIdxNoSeek is not
+**   a valid cursor number, the position of iDataCur should be preserved
+**   instead.
+**
+** iIdxNoSeek:
+**   If iIdxNoSeek is a valid cursor number (>=0), then it identifies an
+**   index cursor (from within array of cursors starting at iIdxCur) that
+**   already points to the index entry to be deleted.
 */
 SQLITE_PRIVATE void sqlite3GenerateRowDelete(
   Parse *pParse,     /* Parsing context */
@@ -97307,7 +98315,8 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
   i16 nPk,           /* Number of PRIMARY KEY memory cells */
   u8 count,          /* If non-zero, increment the row change counter */
   u8 onconf,         /* Default ON CONFLICT policy for triggers */
-  u8 bNoSeek         /* iDataCur is already pointing to the row to delete */
+  u8 eMode,          /* ONEPASS_OFF, _SINGLE, or _MULTI.  See above */
+  int iIdxNoSeek     /* Cursor number of cursor that does not need seeking */
 ){
   Vdbe *v = pParse->pVdbe;        /* Vdbe */
   int iOld = 0;                   /* First register in OLD.* array */
@@ -97324,7 +98333,7 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
   ** not attempt to delete it or fire any DELETE triggers.  */
   iLabel = sqlite3VdbeMakeLabel(v);
   opSeek = HasRowid(pTab) ? OP_NotExists : OP_NotFound;
-  if( !bNoSeek ){
+  if( eMode==ONEPASS_OFF ){
     sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk);
     VdbeCoverageIf(v, opSeek==OP_NotExists);
     VdbeCoverageIf(v, opSeek==OP_NotFound);
@@ -97384,11 +98393,15 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
   ** a view (in which case the only effect of the DELETE statement is to
   ** fire the INSTEAD OF triggers).  */ 
   if( pTab->pSelect==0 ){
-    sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, 0);
+    sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek);
     sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
     if( count ){
       sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
     }
+    if( iIdxNoSeek>=0 ){
+      sqlite3VdbeAddOp1(v, OP_Delete, iIdxNoSeek);
+    }
+    sqlite3VdbeChangeP5(v, eMode==ONEPASS_MULTI);
   }
 
   /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
@@ -97431,7 +98444,8 @@ SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(
   Table *pTab,       /* Table containing the row to be deleted */
   int iDataCur,      /* Cursor of table holding data. */
   int iIdxCur,       /* First index cursor */
-  int *aRegIdx       /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */
+  int *aRegIdx,      /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */
+  int iIdxNoSeek     /* Do not delete from this cursor */
 ){
   int i;             /* Index loop counter */
   int r1 = -1;       /* Register holding an index key */
@@ -97447,11 +98461,12 @@ SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(
     assert( iIdxCur+i!=iDataCur || pPk==pIdx );
     if( aRegIdx!=0 && aRegIdx[i]==0 ) continue;
     if( pIdx==pPk ) continue;
+    if( iIdxCur+i==iIdxNoSeek ) continue;
     VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName));
     r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1,
-                                 &iPartIdxLabel, pPrior, r1);
+        &iPartIdxLabel, pPrior, r1);
     sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
-                      pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
+        pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
     sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
     pPrior = pIdx;
   }
@@ -97500,14 +98515,13 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey(
 ){
   Vdbe *v = pParse->pVdbe;
   int j;
-  Table *pTab = pIdx->pTable;
   int regBase;
   int nCol;
 
   if( piPartIdxLabel ){
     if( pIdx->pPartIdxWhere ){
       *piPartIdxLabel = sqlite3VdbeMakeLabel(v);
-      pParse->iPartIdxTab = iDataCur;
+      pParse->iSelfTab = iDataCur;
       sqlite3ExprCachePush(pParse);
       sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, 
                             SQLITE_JUMPIFNULL);
@@ -97519,9 +98533,14 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey(
   regBase = sqlite3GetTempRange(pParse, nCol);
   if( pPrior && (regBase!=regPrior || pPrior->pPartIdxWhere) ) pPrior = 0;
   for(j=0; j<nCol; j++){
-    if( pPrior && pPrior->aiColumn[j]==pIdx->aiColumn[j] ) continue;
-    sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pIdx->aiColumn[j],
-                                    regBase+j);
+    if( pPrior
+     && pPrior->aiColumn[j]==pIdx->aiColumn[j]
+     && pPrior->aiColumn[j]!=XN_EXPR
+    ){
+      /* This column was already computed by the previous index */
+      continue;
+    }
+    sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iDataCur, j, regBase+j);
     /* If the column affinity is REAL but the number is an integer, then it
     ** might be stored in the table as an integer (using a compact
     ** representation) then converted to REAL by an OP_RealAffinity opcode.
@@ -99290,15 +100309,15 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
     VFUNCTION(random,            0, 0, 0, randomFunc       ),
     VFUNCTION(randomblob,        1, 0, 0, randomBlob       ),
     FUNCTION(nullif,             2, 0, 1, nullifFunc       ),
-    FUNCTION(sqlite_version,     0, 0, 0, versionFunc      ),
-    FUNCTION(sqlite_source_id,   0, 0, 0, sourceidFunc     ),
+    DFUNCTION(sqlite_version,    0, 0, 0, versionFunc      ),
+    DFUNCTION(sqlite_source_id,  0, 0, 0, sourceidFunc     ),
     FUNCTION(sqlite_log,         2, 0, 0, errlogFunc       ),
 #if SQLITE_USER_AUTHENTICATION
     FUNCTION(sqlite_crypt,       2, 0, 0, sqlite3CryptFunc ),
 #endif
 #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
-    FUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc  ),
-    FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc  ),
+    DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc  ),
+    DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc  ),
 #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
     FUNCTION(quote,              1, 0, 0, quoteFunc        ),
     VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
@@ -99310,8 +100329,8 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
     FUNCTION(soundex,            1, 0, 0, soundexFunc      ),
   #endif
   #ifndef SQLITE_OMIT_LOAD_EXTENSION
-    FUNCTION(load_extension,     1, 0, 0, loadExt          ),
-    FUNCTION(load_extension,     2, 0, 0, loadExt          ),
+    VFUNCTION(load_extension,    1, 0, 0, loadExt          ),
+    VFUNCTION(load_extension,    2, 0, 0, loadExt          ),
   #endif
     AGGREGATE(sum,               1, 0, 0, sumStep,         sumFinalize    ),
     AGGREGATE(total,             1, 0, 0, sumStep,         totalFinalize    ),
@@ -99604,6 +100623,8 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(
           char *zDfltColl;                  /* Def. collation for column */
           char *zIdxCol;                    /* Name of indexed column */
 
+          if( iCol<0 ) break; /* No foreign keys against expression indexes */
+
           /* If the index uses a collation sequence that is different from
           ** the default collation sequence for the column, this index is
           ** unusable. Bail out early in this case.  */
@@ -99726,7 +100747,7 @@ static void fkLookupParent(
   
       sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
       sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regTemp); VdbeCoverage(v);
-      sqlite3VdbeAddOp2(v, OP_Goto, 0, iOk);
+      sqlite3VdbeGoto(v, iOk);
       sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
       sqlite3VdbeJumpHere(v, iMustBeInt);
       sqlite3ReleaseTempReg(pParse, regTemp);
@@ -99756,6 +100777,7 @@ static void fkLookupParent(
         for(i=0; i<nCol; i++){
           int iChild = aiCol[i]+1+regData;
           int iParent = pIdx->aiColumn[i]+1+regData;
+          assert( pIdx->aiColumn[i]>=0 );
           assert( aiCol[i]!=pTab->iPKey );
           if( pIdx->aiColumn[i]==pTab->iPKey ){
             /* The parent key is a composite key that includes the IPK column */
@@ -99764,11 +100786,11 @@ static void fkLookupParent(
           sqlite3VdbeAddOp3(v, OP_Ne, iChild, iJump, iParent); VdbeCoverage(v);
           sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
         }
-        sqlite3VdbeAddOp2(v, OP_Goto, 0, iOk);
+        sqlite3VdbeGoto(v, iOk);
       }
   
       sqlite3VdbeAddOp4(v, OP_MakeRecord, regTemp, nCol, regRec,
-                        sqlite3IndexAffinityStr(v,pIdx), nCol);
+                        sqlite3IndexAffinityStr(pParse->db,pIdx), nCol);
       sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regRec, 0); VdbeCoverage(v);
   
       sqlite3ReleaseTempReg(pParse, regRec);
@@ -99964,6 +100986,7 @@ static void fkScanChildren(
       assert( pIdx!=0 );
       for(i=0; i<pPk->nKeyCol; i++){
         i16 iCol = pIdx->aiColumn[i];
+        assert( iCol>=0 );
         pLeft = exprTableRegister(pParse, pTab, regData, iCol);
         pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, iCol);
         pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight, 0);
@@ -100283,6 +101306,7 @@ SQLITE_PRIVATE void sqlite3FkCheck(
       if( aiCol[i]==pTab->iPKey ){
         aiCol[i] = -1;
       }
+      assert( pIdx==0 || pIdx->aiColumn[i]>=0 );
 #ifndef SQLITE_OMIT_AUTHORIZATION
       /* Request permission to read the parent key columns. If the 
       ** authorization callback returns SQLITE_IGNORE, behave as if any
@@ -100414,7 +101438,10 @@ SQLITE_PRIVATE u32 sqlite3FkOldmask(
       Index *pIdx = 0;
       sqlite3FkLocateIndex(pParse, pTab, p, &pIdx, 0);
       if( pIdx ){
-        for(i=0; i<pIdx->nKeyCol; i++) mask |= COLUMN_MASK(pIdx->aiColumn[i]);
+        for(i=0; i<pIdx->nKeyCol; i++){
+          assert( pIdx->aiColumn[i]>=0 );
+          mask |= COLUMN_MASK(pIdx->aiColumn[i]);
+        }
       }
     }
   }
@@ -100537,6 +101564,7 @@ static Trigger *fkActionTrigger(
       iFromCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom;
       assert( iFromCol>=0 );
       assert( pIdx!=0 || (pTab->iPKey>=0 && pTab->iPKey<pTab->nCol) );
+      assert( pIdx==0 || pIdx->aiColumn[i]>=0 );
       tToCol.z = pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zName;
       tFromCol.z = pFKey->pFrom->aCol[iFromCol].zName;
 
@@ -100825,7 +101853,7 @@ SQLITE_PRIVATE void sqlite3OpenTable(
 ** is managed along with the rest of the Index structure. It will be
 ** released when sqlite3DeleteIndex() is called.
 */
-SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
+SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
   if( !pIdx->zColAff ){
     /* The first time a column affinity string for a particular index is
     ** required, it is allocated and populated here. It is then stored as
@@ -100837,7 +101865,6 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
     */
     int n;
     Table *pTab = pIdx->pTable;
-    sqlite3 *db = sqlite3VdbeDb(v);
     pIdx->zColAff = (char *)sqlite3DbMallocRaw(0, pIdx->nColumn+1);
     if( !pIdx->zColAff ){
       db->mallocFailed = 1;
@@ -100845,7 +101872,18 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
     }
     for(n=0; n<pIdx->nColumn; n++){
       i16 x = pIdx->aiColumn[n];
-      pIdx->zColAff[n] = x<0 ? SQLITE_AFF_INTEGER : pTab->aCol[x].affinity;
+      if( x>=0 ){
+        pIdx->zColAff[n] = pTab->aCol[x].affinity;
+      }else if( x==XN_ROWID ){
+        pIdx->zColAff[n] = SQLITE_AFF_INTEGER;
+      }else{
+        char aff;
+        assert( x==XN_EXPR );
+        assert( pIdx->aColExpr!=0 );
+        aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
+        if( aff==0 ) aff = SQLITE_AFF_BLOB;
+        pIdx->zColAff[n] = aff;
+      }
     }
     pIdx->zColAff[n] = 0;
   }
@@ -101006,7 +102044,7 @@ SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){
   /* This routine is never called during trigger-generation.  It is
   ** only called from the top-level */
   assert( pParse->pTriggerTab==0 );
-  assert( pParse==sqlite3ParseToplevel(pParse) );
+  assert( sqlite3IsToplevel(pParse) );
 
   assert( v );   /* We failed long ago if this is not so */
   for(p = pParse->pAinc; p; p = p->pNext){
@@ -101016,14 +102054,14 @@ SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){
     sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
     sqlite3VdbeAddOp3(v, OP_Null, 0, memId, memId+1);
     addr = sqlite3VdbeCurrentAddr(v);
-    sqlite3VdbeAddOp4(v, OP_String8, 0, memId-1, 0, p->pTab->zName, 0);
+    sqlite3VdbeLoadString(v, memId-1, p->pTab->zName);
     sqlite3VdbeAddOp2(v, OP_Rewind, 0, addr+9); VdbeCoverage(v);
     sqlite3VdbeAddOp3(v, OP_Column, 0, 0, memId);
     sqlite3VdbeAddOp3(v, OP_Ne, memId-1, addr+7, memId); VdbeCoverage(v);
     sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL);
     sqlite3VdbeAddOp2(v, OP_Rowid, 0, memId+1);
     sqlite3VdbeAddOp3(v, OP_Column, 0, 1, memId);
-    sqlite3VdbeAddOp2(v, OP_Goto, 0, addr+9);
+    sqlite3VdbeGoto(v, addr+9);
     sqlite3VdbeAddOp2(v, OP_Next, 0, addr+2); VdbeCoverage(v);
     sqlite3VdbeAddOp2(v, OP_Integer, 0, memId);
     sqlite3VdbeAddOp0(v, OP_Close);
@@ -101059,16 +102097,16 @@ SQLITE_PRIVATE void sqlite3AutoincrementEnd(Parse *pParse){
   assert( v );
   for(p = pParse->pAinc; p; p = p->pNext){
     Db *pDb = &db->aDb[p->iDb];
-    int j1;
+    int addr1;
     int iRec;
     int memId = p->regCtr;
 
     iRec = sqlite3GetTempReg(pParse);
     assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) );
     sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
-    j1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); VdbeCoverage(v);
+    addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); VdbeCoverage(v);
     sqlite3VdbeAddOp2(v, OP_NewRowid, 0, memId+1);
-    sqlite3VdbeJumpHere(v, j1);
+    sqlite3VdbeJumpHere(v, addr1);
     sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, iRec);
     sqlite3VdbeAddOp3(v, OP_Insert, 0, iRec, memId+1);
     sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
@@ -101447,7 +102485,7 @@ SQLITE_PRIVATE void sqlite3Insert(
       sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec);
       sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regTempRowid);
       sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec, regTempRowid);
-      sqlite3VdbeAddOp2(v, OP_Goto, 0, addrL);
+      sqlite3VdbeGoto(v, addrL);
       sqlite3VdbeJumpHere(v, addrL);
       sqlite3ReleaseTempReg(pParse, regRec);
       sqlite3ReleaseTempReg(pParse, regTempRowid);
@@ -101461,11 +102499,13 @@ SQLITE_PRIVATE void sqlite3Insert(
     sNC.pParse = pParse;
     srcTab = -1;
     assert( useTempTable==0 );
-    nColumn = pList ? pList->nExpr : 0;
-    for(i=0; i<nColumn; i++){
-      if( sqlite3ResolveExprNames(&sNC, pList->a[i].pExpr) ){
+    if( pList ){
+      nColumn = pList->nExpr;
+      if( sqlite3ResolveExprListNames(&sNC, pList) ){
         goto insert_cleanup;
       }
+    }else{
+      nColumn = 0;
     }
   }
 
@@ -101558,7 +102598,7 @@ SQLITE_PRIVATE void sqlite3Insert(
     if( ipkColumn<0 ){
       sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols);
     }else{
-      int j1;
+      int addr1;
       assert( !withoutRowid );
       if( useTempTable ){
         sqlite3VdbeAddOp3(v, OP_Column, srcTab, ipkColumn, regCols);
@@ -101566,9 +102606,9 @@ SQLITE_PRIVATE void sqlite3Insert(
         assert( pSelect==0 );  /* Otherwise useTempTable is true */
         sqlite3ExprCode(pParse, pList->a[ipkColumn].pExpr, regCols);
       }
-      j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols); VdbeCoverage(v);
+      addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols); VdbeCoverage(v);
       sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols);
-      sqlite3VdbeJumpHere(v, j1);
+      sqlite3VdbeJumpHere(v, addr1);
       sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols); VdbeCoverage(v);
     }
 
@@ -101642,14 +102682,14 @@ SQLITE_PRIVATE void sqlite3Insert(
       ** to generate a unique primary key value.
       */
       if( !appendFlag ){
-        int j1;
+        int addr1;
         if( !IsVirtual(pTab) ){
-          j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid); VdbeCoverage(v);
+          addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid); VdbeCoverage(v);
           sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc);
-          sqlite3VdbeJumpHere(v, j1);
+          sqlite3VdbeJumpHere(v, addr1);
         }else{
-          j1 = sqlite3VdbeCurrentAddr(v);
-          sqlite3VdbeAddOp2(v, OP_IsNull, regRowid, j1+2); VdbeCoverage(v);
+          addr1 = sqlite3VdbeCurrentAddr(v);
+          sqlite3VdbeAddOp2(v, OP_IsNull, regRowid, addr1+2); VdbeCoverage(v);
         }
         sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid); VdbeCoverage(v);
       }
@@ -101746,7 +102786,7 @@ SQLITE_PRIVATE void sqlite3Insert(
     sqlite3VdbeJumpHere(v, addrInsTop);
     sqlite3VdbeAddOp1(v, OP_Close, srcTab);
   }else if( pSelect ){
-    sqlite3VdbeAddOp2(v, OP_Goto, 0, addrCont);
+    sqlite3VdbeGoto(v, addrCont);
     sqlite3VdbeJumpHere(v, addrInsTop);
   }
 
@@ -101903,7 +102943,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
   int ix;              /* Index loop counter */
   int nCol;            /* Number of columns */
   int onError;         /* Conflict resolution strategy */
-  int j1;              /* Address of jump instruction */
+  int addr1;           /* Address of jump instruction */
   int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
   int nPkField;        /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
   int ipkTop = 0;      /* Top of the rowid change constraint check */
@@ -101974,9 +103014,10 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
       }
       default: {
         assert( onError==OE_Replace );
-        j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regNewData+1+i); VdbeCoverage(v);
+        addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regNewData+1+i);
+           VdbeCoverage(v);
         sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regNewData+1+i);
-        sqlite3VdbeJumpHere(v, j1);
+        sqlite3VdbeJumpHere(v, addr1);
         break;
       }
     }
@@ -101993,7 +103034,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
       int allOk = sqlite3VdbeMakeLabel(v);
       sqlite3ExprIfTrue(pParse, pCheck->a[i].pExpr, allOk, SQLITE_JUMPIFNULL);
       if( onError==OE_Ignore ){
-        sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
+        sqlite3VdbeGoto(v, ignoreDest);
       }else{
         char *zName = pCheck->a[i].zName;
         if( zName==0 ) zName = pTab->zName;
@@ -102091,17 +103132,20 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
         if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
           sqlite3MultiWrite(pParse);
           sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
-                                   regNewData, 1, 0, OE_Replace, 1);
-        }else if( pTab->pIndex ){
-          sqlite3MultiWrite(pParse);
-          sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, 0);
+                                   regNewData, 1, 0, OE_Replace,
+                                   ONEPASS_SINGLE, -1);
+        }else{
+          if( pTab->pIndex ){
+            sqlite3MultiWrite(pParse);
+            sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,-1);
+          }
         }
         seenReplace = 1;
         break;
       }
       case OE_Ignore: {
         /*assert( seenReplace==0 );*/
-        sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
+        sqlite3VdbeGoto(v, ignoreDest);
         break;
       }
     }
@@ -102149,15 +103193,22 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
     for(i=0; i<pIdx->nColumn; i++){
       int iField = pIdx->aiColumn[i];
       int x;
-      if( iField<0 || iField==pTab->iPKey ){
-        if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */
-        x = regNewData;
-        regRowid =  pIdx->pPartIdxWhere ? -1 : regIdx+i;
+      if( iField==XN_EXPR ){
+        pParse->ckBase = regNewData+1;
+        sqlite3ExprCode(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i);
+        pParse->ckBase = 0;
+        VdbeComment((v, "%s column %d", pIdx->zName, i));
       }else{
-        x = iField + regNewData + 1;
+        if( iField==XN_ROWID || iField==pTab->iPKey ){
+          if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */
+          x = regNewData;
+          regRowid =  pIdx->pPartIdxWhere ? -1 : regIdx+i;
+        }else{
+          x = iField + regNewData + 1;
+        }
+        sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i);
+        VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName));
       }
-      sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i);
-      VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName));
     }
     sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
     VdbeComment((v, "for %s", pIdx->zName));
@@ -102207,6 +103258,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
         ** store it in registers regR..regR+nPk-1 */
         if( pIdx!=pPk ){
           for(i=0; i<pPk->nKeyCol; i++){
+            assert( pPk->aiColumn[i]>=0 );
             x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
             sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
             VdbeComment((v, "%s.%s", pTab->zName,
@@ -102228,6 +103280,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
           for(i=0; i<pPk->nKeyCol; i++){
             char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]);
             x = pPk->aiColumn[i];
+            assert( x>=0 );
             if( i==(pPk->nKeyCol-1) ){
               addrJump = addrUniqueOk;
               op = OP_Eq;
@@ -102254,7 +103307,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
         break;
       }
       case OE_Ignore: {
-        sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
+        sqlite3VdbeGoto(v, ignoreDest);
         break;
       }
       default: {
@@ -102265,7 +103318,8 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
           pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
         }
         sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
-                                 regR, nPkField, 0, OE_Replace, pIdx==pPk);
+            regR, nPkField, 0, OE_Replace,
+            (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), -1);
         seenReplace = 1;
         break;
       }
@@ -102275,7 +103329,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
     if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);
   }
   if( ipkTop ){
-    sqlite3VdbeAddOp2(v, OP_Goto, 0, ipkTop+1);
+    sqlite3VdbeGoto(v, ipkTop+1);
     sqlite3VdbeJumpHere(v, ipkBottom);
   }
   
@@ -102478,6 +103532,13 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){
     if( pSrc->aiColumn[i]!=pDest->aiColumn[i] ){
       return 0;   /* Different columns indexed */
     }
+    if( pSrc->aiColumn[i]==XN_EXPR ){
+      assert( pSrc->aColExpr!=0 && pDest->aColExpr!=0 );
+      if( sqlite3ExprCompare(pSrc->aColExpr->a[i].pExpr,
+                             pDest->aColExpr->a[i].pExpr, -1)!=0 ){
+        return 0;   /* Different expressions in the index */
+      }
+    }
     if( pSrc->aSortOrder[i]!=pDest->aSortOrder[i] ){
       return 0;   /* Different sort orders */
     }
@@ -102721,7 +103782,7 @@ static int xferOptimization(
     ** (3) onError is something other than OE_Abort and OE_Rollback.
     */
     addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iDest, 0); VdbeCoverage(v);
-    emptyDestTest = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
+    emptyDestTest = sqlite3VdbeAddOp0(v, OP_Goto);
     sqlite3VdbeJumpHere(v, addr1);
   }
   if( HasRowid(pSrc) ){
@@ -103258,6 +104319,9 @@ struct sqlite3_api_routines {
   void (*value_free)(sqlite3_value*);
   int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);
   int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);
+  /* Version 3.9.0 and later */
+  unsigned int (*value_subtype)(sqlite3_value*);
+  void (*result_subtype)(sqlite3_context*,unsigned int);
 };
 
 /*
@@ -103271,7 +104335,7 @@ struct sqlite3_api_routines {
 ** the API.  So the redefinition macros are only valid if the
 ** SQLITE_CORE macros is undefined.
 */
-#ifndef SQLITE_CORE
+#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
 #define sqlite3_aggregate_context      sqlite3_api->aggregate_context
 #ifndef SQLITE_OMIT_DEPRECATED
 #define sqlite3_aggregate_count        sqlite3_api->aggregate_count
@@ -103398,6 +104462,7 @@ struct sqlite3_api_routines {
 #define sqlite3_value_text16le         sqlite3_api->value_text16le
 #define sqlite3_value_type             sqlite3_api->value_type
 #define sqlite3_vmprintf               sqlite3_api->vmprintf
+#define sqlite3_vsnprintf              sqlite3_api->vsnprintf
 #define sqlite3_overload_function      sqlite3_api->overload_function
 #define sqlite3_prepare_v2             sqlite3_api->prepare_v2
 #define sqlite3_prepare16_v2           sqlite3_api->prepare16_v2
@@ -103493,9 +104558,12 @@ struct sqlite3_api_routines {
 #define sqlite3_value_free             sqlite3_api->value_free
 #define sqlite3_result_zeroblob64      sqlite3_api->result_zeroblob64
 #define sqlite3_bind_zeroblob64        sqlite3_api->bind_zeroblob64
-#endif /* SQLITE_CORE */
+/* Version 3.9.0 and later */
+#define sqlite3_value_subtype          sqlite3_api->value_subtype
+#define sqlite3_result_subtype         sqlite3_api->result_subtype
+#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
 
-#ifndef SQLITE_CORE
+#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
   /* This case when the file really is being compiled as a loadable 
   ** extension */
 # define SQLITE_EXTENSION_INIT1     const sqlite3_api_routines *sqlite3_api=0;
@@ -103904,7 +104972,10 @@ static const sqlite3_api_routines sqlite3Apis = {
   (sqlite3_value*(*)(const sqlite3_value*))sqlite3_value_dup,
   sqlite3_value_free,
   sqlite3_result_zeroblob64,
-  sqlite3_bind_zeroblob64
+  sqlite3_bind_zeroblob64,
+  /* Version 3.9.0 and later */
+  sqlite3_value_subtype,
+  sqlite3_result_subtype
 };
 
 /*
@@ -104109,7 +105180,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int ono
 ** dummy pointer.
 */
 #ifdef SQLITE_OMIT_LOAD_EXTENSION
-static const sqlite3_api_routines sqlite3Apis = { 0 };
+static const sqlite3_api_routines sqlite3Apis;
 #endif
 
 
@@ -104901,20 +105972,46 @@ static int changeTempStorage(Parse *pParse, const char *zStorageType){
 }
 #endif /* SQLITE_PAGER_PRAGMAS */
 
+/*
+** Set the names of the first N columns to the values in azCol[]
+*/
+static void setAllColumnNames(
+  Vdbe *v,               /* The query under construction */
+  int N,                 /* Number of columns */
+  const char **azCol     /* Names of columns */
+){
+  int i;
+  sqlite3VdbeSetNumCols(v, N);
+  for(i=0; i<N; i++){
+    sqlite3VdbeSetColName(v, i, COLNAME_NAME, azCol[i], SQLITE_STATIC);
+  }
+}
+static void setOneColumnName(Vdbe *v, const char *z){
+  setAllColumnNames(v, 1, &z);
+}
+
 /*
 ** Generate code to return a single integer value.
 */
-static void returnSingleInt(Parse *pParse, const char *zLabel, i64 value){
-  Vdbe *v = sqlite3GetVdbe(pParse);
-  int nMem = ++pParse->nMem;
-  i64 *pI64 = sqlite3DbMallocRaw(pParse->db, sizeof(value));
-  if( pI64 ){
-    memcpy(pI64, &value, sizeof(value));
+static void returnSingleInt(Vdbe *v, const char *zLabel, i64 value){
+  sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, 1, 0, (const u8*)&value, P4_INT64);
+  setOneColumnName(v, zLabel);
+  sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
+}
+
+/*
+** Generate code to return a single text value.
+*/
+static void returnSingleText(
+  Vdbe *v,                /* Prepared statement under construction */
+  const char *zLabel,     /* Name of the result column */
+  const char *zValue      /* Value to be returned */
+){
+  if( zValue ){
+    sqlite3VdbeLoadString(v, 1, (const char*)zValue);
+    setOneColumnName(v, zLabel);
+    sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
   }
-  sqlite3VdbeAddOp4(v, OP_Int64, 0, nMem, 0, (char*)pI64, P4_INT64);
-  sqlite3VdbeSetNumCols(v, 1);
-  sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, SQLITE_STATIC);
-  sqlite3VdbeAddOp2(v, OP_ResultRow, nMem, 1);
 }
 
 
@@ -105078,14 +106175,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
   db->busyHandler.nBusy = 0;
   rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl);
   if( rc==SQLITE_OK ){
-    if( aFcntl[0] ){
-      int nMem = ++pParse->nMem;
-      sqlite3VdbeAddOp4(v, OP_String8, 0, nMem, 0, aFcntl[0], 0);
-      sqlite3VdbeSetNumCols(v, 1);
-      sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "result", SQLITE_STATIC);
-      sqlite3VdbeAddOp2(v, OP_ResultRow, nMem, 1);
-      sqlite3_free(aFcntl[0]);
-    }
+    returnSingleText(v, "result", aFcntl[0]);
+    sqlite3_free(aFcntl[0]);
     goto pragma_out;
   }
   if( rc!=SQLITE_NOTFOUND ){
@@ -105155,8 +106246,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
     int addr;
     sqlite3VdbeUsesBtree(v, iDb);
     if( !zRight ){
-      sqlite3VdbeSetNumCols(v, 1);
-      sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", SQLITE_STATIC);
+      setOneColumnName(v, "cache_size");
       pParse->nMem += 2;
       addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize,iLn);
       sqlite3VdbeChangeP1(v, addr, iDb);
@@ -105190,7 +106280,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
     assert( pBt!=0 );
     if( !zRight ){
       int size = ALWAYS(pBt) ? sqlite3BtreeGetPageSize(pBt) : 0;
-      returnSingleInt(pParse, "page_size", size);
+      returnSingleInt(v, "page_size", size);
     }else{
       /* Malloc may fail when setting the page-size, as there is an internal
       ** buffer that the pager module resizes using sqlite3_realloc().
@@ -105225,7 +106315,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
       }
     }
     b = sqlite3BtreeSecureDelete(pBt, b);
-    returnSingleInt(pParse, "secure_delete", b);
+    returnSingleInt(v, "secure_delete", b);
     break;
   }
 
@@ -105304,10 +106394,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
     if( eMode==PAGER_LOCKINGMODE_EXCLUSIVE ){
       zRet = "exclusive";
     }
-    sqlite3VdbeSetNumCols(v, 1);
-    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "locking_mode", SQLITE_STATIC);
-    sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, zRet, 0);
-    sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
+    returnSingleText(v, "locking_mode", zRet);
     break;
   }
 
@@ -105320,9 +106407,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
     int eMode;        /* One of the PAGER_JOURNALMODE_XXX symbols */
     int ii;           /* Loop counter */
 
-    sqlite3VdbeSetNumCols(v, 1);
-    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", SQLITE_STATIC);
-
+    setOneColumnName(v, "journal_mode");
     if( zRight==0 ){
       /* If there is no "=MODE" part of the pragma, do a query for the
       ** current mode */
@@ -105368,7 +106453,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
       if( iLimit<-1 ) iLimit = -1;
     }
     iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit);
-    returnSingleInt(pParse, "journal_size_limit", iLimit);
+    returnSingleInt(v, "journal_size_limit", iLimit);
     break;
   }
 
@@ -105386,7 +106471,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
     Btree *pBt = pDb->pBt;
     assert( pBt!=0 );
     if( !zRight ){
-      returnSingleInt(pParse, "auto_vacuum", sqlite3BtreeGetAutoVacuum(pBt));
+      returnSingleInt(v, "auto_vacuum", sqlite3BtreeGetAutoVacuum(pBt));
     }else{
       int eAuto = getAutoVacuum(zRight);
       assert( eAuto>=0 && eAuto<=2 );
@@ -105464,7 +106549,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
     assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
     if( !zRight ){
       if( sqlite3ReadSchema(pParse) ) goto pragma_out;
-      returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size);
+      returnSingleInt(v, "cache_size", pDb->pSchema->cache_size);
     }else{
       int size = sqlite3Atoi(zRight);
       pDb->pSchema->cache_size = size;
@@ -105510,7 +106595,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
     rc = SQLITE_OK;
 #endif
     if( rc==SQLITE_OK ){
-      returnSingleInt(pParse, "mmap_size", sz);
+      returnSingleInt(v, "mmap_size", sz);
     }else if( rc!=SQLITE_NOTFOUND ){
       pParse->nErr++;
       pParse->rc = rc;
@@ -105531,7 +106616,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
   */
   case PragTyp_TEMP_STORE: {
     if( !zRight ){
-      returnSingleInt(pParse, "temp_store", db->temp_store);
+      returnSingleInt(v, "temp_store", db->temp_store);
     }else{
       changeTempStorage(pParse, zRight);
     }
@@ -105550,13 +106635,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
   */
   case PragTyp_TEMP_STORE_DIRECTORY: {
     if( !zRight ){
-      if( sqlite3_temp_directory ){
-        sqlite3VdbeSetNumCols(v, 1);
-        sqlite3VdbeSetColName(v, 0, COLNAME_NAME, 
-            "temp_store_directory", SQLITE_STATIC);
-        sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, sqlite3_temp_directory, 0);
-        sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
-      }
+      returnSingleText(v, "temp_store_directory", sqlite3_temp_directory);
     }else{
 #ifndef SQLITE_OMIT_WSD
       if( zRight[0] ){
@@ -105600,13 +106679,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
   */
   case PragTyp_DATA_STORE_DIRECTORY: {
     if( !zRight ){
-      if( sqlite3_data_directory ){
-        sqlite3VdbeSetNumCols(v, 1);
-        sqlite3VdbeSetColName(v, 0, COLNAME_NAME, 
-            "data_store_directory", SQLITE_STATIC);
-        sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, sqlite3_data_directory, 0);
-        sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
-      }
+      returnSingleText(v, "data_store_directory", sqlite3_data_directory);
     }else{
 #ifndef SQLITE_OMIT_WSD
       if( zRight[0] ){
@@ -105645,14 +106718,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
       sqlite3_file *pFile = sqlite3PagerFile(pPager);
       sqlite3OsFileControlHint(pFile, SQLITE_GET_LOCKPROXYFILE, 
                            &proxy_file_path);
-      
-      if( proxy_file_path ){
-        sqlite3VdbeSetNumCols(v, 1);
-        sqlite3VdbeSetColName(v, 0, COLNAME_NAME, 
-                              "lock_proxy_file", SQLITE_STATIC);
-        sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, proxy_file_path, 0);
-        sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
-      }
+      returnSingleText(v, "lock_proxy_file", proxy_file_path);
     }else{
       Pager *pPager = sqlite3BtreePager(pDb->pBt);
       sqlite3_file *pFile = sqlite3PagerFile(pPager);
@@ -105684,7 +106750,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
   */
   case PragTyp_SYNCHRONOUS: {
     if( !zRight ){
-      returnSingleInt(pParse, "synchronous", pDb->safety_level-1);
+      returnSingleInt(v, "synchronous", pDb->safety_level-1);
     }else{
       if( !db->autoCommit ){
         sqlite3ErrorMsg(pParse, 
@@ -105703,7 +106769,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
 #ifndef SQLITE_OMIT_FLAG_PRAGMAS
   case PragTyp_FLAG: {
     if( zRight==0 ){
-      returnSingleInt(pParse, pPragma->zName, (db->flags & pPragma->iArg)!=0 );
+      returnSingleInt(v, pPragma->zName, (db->flags & pPragma->iArg)!=0 );
     }else{
       int mask = pPragma->iArg;    /* Mask of bits to set or clear. */
       if( db->autoCommit==0 ){
@@ -105753,35 +106819,22 @@ SQLITE_PRIVATE void sqlite3Pragma(
     Table *pTab;
     pTab = sqlite3FindTable(db, zRight, zDb);
     if( pTab ){
+      static const char *azCol[] = {
+         "cid", "name", "type", "notnull", "dflt_value", "pk"
+      };
       int i, k;
       int nHidden = 0;
       Column *pCol;
       Index *pPk = sqlite3PrimaryKeyIndex(pTab);
-      sqlite3VdbeSetNumCols(v, 6);
       pParse->nMem = 6;
       sqlite3CodeVerifySchema(pParse, iDb);
-      sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", SQLITE_STATIC);
-      sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
-      sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", SQLITE_STATIC);
-      sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "notnull", SQLITE_STATIC);
-      sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "dflt_value", SQLITE_STATIC);
-      sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "pk", SQLITE_STATIC);
+      setAllColumnNames(v, 6, azCol); assert( 6==ArraySize(azCol) );
       sqlite3ViewGetColumnNames(pParse, pTab);
       for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
         if( IsHiddenColumn(pCol) ){
           nHidden++;
           continue;
         }
-        sqlite3VdbeAddOp2(v, OP_Integer, i-nHidden, 1);
-        sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pCol->zName, 0);
-        sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
-           pCol->zType ? pCol->zType : "", 0);
-        sqlite3VdbeAddOp2(v, OP_Integer, (pCol->notNull ? 1 : 0), 4);
-        if( pCol->zDflt ){
-          sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)pCol->zDflt, 0);
-        }else{
-          sqlite3VdbeAddOp2(v, OP_Null, 0, 5);
-        }
         if( (pCol->colFlags & COLFLAG_PRIMKEY)==0 ){
           k = 0;
         }else if( pPk==0 ){
@@ -105789,7 +106842,13 @@ SQLITE_PRIVATE void sqlite3Pragma(
         }else{
           for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){}
         }
-        sqlite3VdbeAddOp2(v, OP_Integer, k, 6);
+        sqlite3VdbeMultiLoad(v, 1, "issisi",
+               i-nHidden,
+               pCol->zName,
+               pCol->zType ? pCol->zType : "",
+               pCol->notNull ? 1 : 0,
+               pCol->zDflt,
+               k);
         sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
       }
     }
@@ -105797,31 +106856,26 @@ SQLITE_PRIVATE void sqlite3Pragma(
   break;
 
   case PragTyp_STATS: {
+    static const char *azCol[] = { "table", "index", "width", "height" };
     Index *pIdx;
     HashElem *i;
     v = sqlite3GetVdbe(pParse);
-    sqlite3VdbeSetNumCols(v, 4);
     pParse->nMem = 4;
     sqlite3CodeVerifySchema(pParse, iDb);
-    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "table", SQLITE_STATIC);
-    sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "index", SQLITE_STATIC);
-    sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "width", SQLITE_STATIC);
-    sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "height", SQLITE_STATIC);
+    setAllColumnNames(v, 4, azCol);  assert( 4==ArraySize(azCol) );
     for(i=sqliteHashFirst(&pDb->pSchema->tblHash); i; i=sqliteHashNext(i)){
       Table *pTab = sqliteHashData(i);
-      sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, pTab->zName, 0);
-      sqlite3VdbeAddOp2(v, OP_Null, 0, 2);
-      sqlite3VdbeAddOp2(v, OP_Integer,
-                           (int)sqlite3LogEstToInt(pTab->szTabRow), 3);
-      sqlite3VdbeAddOp2(v, OP_Integer, 
-          (int)sqlite3LogEstToInt(pTab->nRowLogEst), 4);
+      sqlite3VdbeMultiLoad(v, 1, "ssii",
+           pTab->zName,
+           0,
+           (int)sqlite3LogEstToInt(pTab->szTabRow),
+           (int)sqlite3LogEstToInt(pTab->nRowLogEst));
       sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
       for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
-        sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
-        sqlite3VdbeAddOp2(v, OP_Integer,
-                             (int)sqlite3LogEstToInt(pIdx->szIdxRow), 3);
-        sqlite3VdbeAddOp2(v, OP_Integer, 
-            (int)sqlite3LogEstToInt(pIdx->aiRowLogEst[0]), 4);
+        sqlite3VdbeMultiLoad(v, 2, "sii",
+           pIdx->zName,
+           (int)sqlite3LogEstToInt(pIdx->szIdxRow),
+           (int)sqlite3LogEstToInt(pIdx->aiRowLogEst[0]));
         sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
       }
     }
@@ -105833,6 +106887,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
     Table *pTab;
     pIdx = sqlite3FindIndex(db, zRight, zDb);
     if( pIdx ){
+      static const char *azCol[] = {
+         "seqno", "cid", "name", "desc", "coll", "key"
+      };
       int i;
       int mx;
       if( pPragma->iArg ){
@@ -105845,29 +106902,18 @@ SQLITE_PRIVATE void sqlite3Pragma(
         pParse->nMem = 3;
       }
       pTab = pIdx->pTable;
-      sqlite3VdbeSetNumCols(v, pParse->nMem);
       sqlite3CodeVerifySchema(pParse, iDb);
-      sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", SQLITE_STATIC);
-      sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", SQLITE_STATIC);
-      sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", SQLITE_STATIC);
-      if( pPragma->iArg ){
-        sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "desc", SQLITE_STATIC);
-        sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "coll", SQLITE_STATIC);
-        sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "key", SQLITE_STATIC);
-      }
+      assert( pParse->nMem<=ArraySize(azCol) );
+      setAllColumnNames(v, pParse->nMem, azCol);
       for(i=0; i<mx; i++){
         i16 cnum = pIdx->aiColumn[i];
-        sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
-        sqlite3VdbeAddOp2(v, OP_Integer, cnum, 2);
-        if( cnum<0 ){
-          sqlite3VdbeAddOp2(v, OP_Null, 0, 3);
-        }else{
-          sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pTab->aCol[cnum].zName, 0);
-        }
+        sqlite3VdbeMultiLoad(v, 1, "iis", i, cnum,
+                             cnum<0 ? 0 : pTab->aCol[cnum].zName);
         if( pPragma->iArg ){
-          sqlite3VdbeAddOp2(v, OP_Integer, pIdx->aSortOrder[i], 4);
-          sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, pIdx->azColl[i], 0);
-          sqlite3VdbeAddOp2(v, OP_Integer, i<pIdx->nKeyCol, 6);
+          sqlite3VdbeMultiLoad(v, 4, "isi",
+            pIdx->aSortOrder[i],
+            pIdx->azColl[i],
+            i<pIdx->nKeyCol);
         }
         sqlite3VdbeAddOp2(v, OP_ResultRow, 1, pParse->nMem);
       }
@@ -105881,22 +106927,21 @@ SQLITE_PRIVATE void sqlite3Pragma(
     int i;
     pTab = sqlite3FindTable(db, zRight, zDb);
     if( pTab ){
+      static const char *azCol[] = {
+        "seq", "name", "unique", "origin", "partial"
+      };
       v = sqlite3GetVdbe(pParse);
-      sqlite3VdbeSetNumCols(v, 5);
       pParse->nMem = 5;
       sqlite3CodeVerifySchema(pParse, iDb);
-      sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
-      sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
-      sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC);
-      sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "origin", SQLITE_STATIC);
-      sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "partial", SQLITE_STATIC);
+      setAllColumnNames(v, 5, azCol);  assert( 5==ArraySize(azCol) );
       for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){
         const char *azOrigin[] = { "c", "u", "pk" };
-        sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
-        sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
-        sqlite3VdbeAddOp2(v, OP_Integer, IsUniqueIndex(pIdx), 3);
-        sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, azOrigin[pIdx->idxType], 0);
-        sqlite3VdbeAddOp2(v, OP_Integer, pIdx->pPartIdxWhere!=0, 5);
+        sqlite3VdbeMultiLoad(v, 1, "isisi",
+           i,
+           pIdx->zName,
+           IsUniqueIndex(pIdx),
+           azOrigin[pIdx->idxType],
+           pIdx->pPartIdxWhere!=0);
         sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5);
       }
     }
@@ -105904,35 +106949,31 @@ SQLITE_PRIVATE void sqlite3Pragma(
   break;
 
   case PragTyp_DATABASE_LIST: {
+    static const char *azCol[] = { "seq", "name", "file" };
     int i;
-    sqlite3VdbeSetNumCols(v, 3);
     pParse->nMem = 3;
-    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
-    sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
-    sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "file", SQLITE_STATIC);
+    setAllColumnNames(v, 3, azCol); assert( 3==ArraySize(azCol) );
     for(i=0; i<db->nDb; i++){
       if( db->aDb[i].pBt==0 ) continue;
       assert( db->aDb[i].zName!=0 );
-      sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
-      sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, db->aDb[i].zName, 0);
-      sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
-           sqlite3BtreeGetFilename(db->aDb[i].pBt), 0);
+      sqlite3VdbeMultiLoad(v, 1, "iss",
+         i,
+         db->aDb[i].zName,
+         sqlite3BtreeGetFilename(db->aDb[i].pBt));
       sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
     }
   }
   break;
 
   case PragTyp_COLLATION_LIST: {
+    static const char *azCol[] = { "seq", "name" };
     int i = 0;
     HashElem *p;
-    sqlite3VdbeSetNumCols(v, 2);
     pParse->nMem = 2;
-    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC);
-    sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC);
+    setAllColumnNames(v, 2, azCol); assert( 2==ArraySize(azCol) );
     for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){
       CollSeq *pColl = (CollSeq *)sqliteHashData(p);
-      sqlite3VdbeAddOp2(v, OP_Integer, i++, 1);
-      sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pColl->zName, 0);
+      sqlite3VdbeMultiLoad(v, 1, "is", i++, pColl->zName);
       sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
     }
   }
@@ -105948,33 +106989,26 @@ SQLITE_PRIVATE void sqlite3Pragma(
       v = sqlite3GetVdbe(pParse);
       pFK = pTab->pFKey;
       if( pFK ){
+        static const char *azCol[] = {
+           "id", "seq", "table", "from", "to", "on_update", "on_delete",
+           "match"
+        };
         int i = 0; 
-        sqlite3VdbeSetNumCols(v, 8);
         pParse->nMem = 8;
         sqlite3CodeVerifySchema(pParse, iDb);
-        sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", SQLITE_STATIC);
-        sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", SQLITE_STATIC);
-        sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", SQLITE_STATIC);
-        sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "from", SQLITE_STATIC);
-        sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "to", SQLITE_STATIC);
-        sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "on_update", SQLITE_STATIC);
-        sqlite3VdbeSetColName(v, 6, COLNAME_NAME, "on_delete", SQLITE_STATIC);
-        sqlite3VdbeSetColName(v, 7, COLNAME_NAME, "match", SQLITE_STATIC);
+        setAllColumnNames(v, 8, azCol); assert( 8==ArraySize(azCol) );
         while(pFK){
           int j;
           for(j=0; j<pFK->nCol; j++){
-            char *zCol = pFK->aCol[j].zCol;
-            char *zOnDelete = (char *)actionName(pFK->aAction[0]);
-            char *zOnUpdate = (char *)actionName(pFK->aAction[1]);
-            sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
-            sqlite3VdbeAddOp2(v, OP_Integer, j, 2);
-            sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pFK->zTo, 0);
-            sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0,
-                              pTab->aCol[pFK->aCol[j].iFrom].zName, 0);
-            sqlite3VdbeAddOp4(v, zCol ? OP_String8 : OP_Null, 0, 5, 0, zCol, 0);
-            sqlite3VdbeAddOp4(v, OP_String8, 0, 6, 0, zOnUpdate, 0);
-            sqlite3VdbeAddOp4(v, OP_String8, 0, 7, 0, zOnDelete, 0);
-            sqlite3VdbeAddOp4(v, OP_String8, 0, 8, 0, "NONE", 0);
+            sqlite3VdbeMultiLoad(v, 1, "iissssss",
+                   i,
+                   j,
+                   pFK->zTo,
+                   pTab->aCol[pFK->aCol[j].iFrom].zName,
+                   pFK->aCol[j].zCol,
+                   actionName(pFK->aAction[1]),  /* ON UPDATE */
+                   actionName(pFK->aAction[0]),  /* ON DELETE */
+                   "NONE");
             sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 8);
           }
           ++i;
@@ -106003,17 +107037,14 @@ SQLITE_PRIVATE void sqlite3Pragma(
     int addrTop;           /* Top of a loop checking foreign keys */
     int addrOk;            /* Jump here if the key is OK */
     int *aiCols;           /* child to parent column mapping */
+    static const char *azCol[] = { "table", "rowid", "parent", "fkid" };
 
     regResult = pParse->nMem+1;
     pParse->nMem += 4;
     regKey = ++pParse->nMem;
     regRow = ++pParse->nMem;
     v = sqlite3GetVdbe(pParse);
-    sqlite3VdbeSetNumCols(v, 4);
-    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "table", SQLITE_STATIC);
-    sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "rowid", SQLITE_STATIC);
-    sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "parent", SQLITE_STATIC);
-    sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "fkid", SQLITE_STATIC);
+    setAllColumnNames(v, 4, azCol); assert( 4==ArraySize(azCol) );
     sqlite3CodeVerifySchema(pParse, iDb);
     k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash);
     while( k ){
@@ -106028,8 +107059,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
       sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
       if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow;
       sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead);
-      sqlite3VdbeAddOp4(v, OP_String8, 0, regResult, 0, pTab->zName,
-                        P4_TRANSIENT);
+      sqlite3VdbeLoadString(v, regResult, pTab->zName);
       for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){
         pParent = sqlite3FindTable(db, pFK->zTo, zDb);
         if( pParent==0 ) continue;
@@ -106074,7 +107104,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
             sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow);
           }
           sqlite3VdbeAddOp3(v, OP_NotExists, i, 0, regRow); VdbeCoverage(v);
-          sqlite3VdbeAddOp2(v, OP_Goto, 0, addrOk);
+          sqlite3VdbeGoto(v, addrOk);
           sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
         }else{
           for(j=0; j<pFK->nCol; j++){
@@ -106084,15 +107114,13 @@ SQLITE_PRIVATE void sqlite3Pragma(
           }
           if( pParent ){
             sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey,
-                              sqlite3IndexAffinityStr(v,pIdx), pFK->nCol);
+                              sqlite3IndexAffinityStr(db,pIdx), pFK->nCol);
             sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
             VdbeCoverage(v);
           }
         }
         sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1);
-        sqlite3VdbeAddOp4(v, OP_String8, 0, regResult+2, 0, 
-                          pFK->zTo, P4_TRANSIENT);
-        sqlite3VdbeAddOp2(v, OP_Integer, i-1, regResult+3);
+        sqlite3VdbeMultiLoad(v, regResult+2, "si", pFK->zTo, i-1);
         sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 4);
         sqlite3VdbeResolveLabel(v, addrOk);
         sqlite3DbFree(db, aiCols);
@@ -106146,8 +107174,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
     */
     static const int iLn = VDBE_OFFSET_LINENO(2);
     static const VdbeOpList endCode[] = {
-      { OP_IfNeg,       1, 0,        0},    /* 0 */
-      { OP_String8,     0, 3,        0},    /* 1 */
+      { OP_AddImm,      1, 0,        0},    /* 0 */
+      { OP_If,          1, 0,        0},    /* 1 */
+      { OP_String8,     0, 3,        0},    /* 2 */
       { OP_ResultRow,   3, 1,        0},
     };
 
@@ -106168,8 +107197,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
 
     /* Initialize the VDBE program */
     pParse->nMem = 6;
-    sqlite3VdbeSetNumCols(v, 1);
-    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", SQLITE_STATIC);
+    setOneColumnName(v, "integrity_check");
 
     /* Set the maximum error count */
     mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
@@ -106291,13 +107319,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
           jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1,
                                       pIdx->nColumn); VdbeCoverage(v);
           sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
-          sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, "row ", P4_STATIC);
+          sqlite3VdbeLoadString(v, 3, "row ");
           sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
-          sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, 
-                            " missing from index ", P4_STATIC);
+          sqlite3VdbeLoadString(v, 4, " missing from index ");
           sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
-          jmp5 = sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0,
-                                   pIdx->zName, P4_TRANSIENT);
+          jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName);
           sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
           sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
           jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v);
@@ -106312,20 +107338,19 @@ SQLITE_PRIVATE void sqlite3Pragma(
             int kk;
             for(kk=0; kk<pIdx->nKeyCol; kk++){
               int iCol = pIdx->aiColumn[kk];
-              assert( iCol>=0 && iCol<pTab->nCol );
-              if( pTab->aCol[iCol].notNull ) continue;
+              assert( iCol!=XN_ROWID && iCol<pTab->nCol );
+              if( iCol>=0 && pTab->aCol[iCol].notNull ) continue;
               sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk);
               VdbeCoverage(v);
             }
             jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v);
-            sqlite3VdbeAddOp2(v, OP_Goto, 0, uniqOk);
+            sqlite3VdbeGoto(v, uniqOk);
             sqlite3VdbeJumpHere(v, jmp6);
             sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1,
                                  pIdx->nKeyCol); VdbeCoverage(v);
             sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
-            sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
-                              "non-unique entry in index ", P4_STATIC);
-            sqlite3VdbeAddOp2(v, OP_Goto, 0, jmp5);
+            sqlite3VdbeLoadString(v, 3, "non-unique entry in index ");
+            sqlite3VdbeGoto(v, jmp5);
             sqlite3VdbeResolveLabel(v, uniqOk);
           }
           sqlite3VdbeJumpHere(v, jmp4);
@@ -106334,8 +107359,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
         sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
         sqlite3VdbeJumpHere(v, loopTop-1);
 #ifndef SQLITE_OMIT_BTREECOUNT
-        sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, 
-                     "wrong # of entries in index ", P4_STATIC);
+        sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
         for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
           if( pPk==pIdx ) continue;
           addr = sqlite3VdbeCurrentAddr(v);
@@ -106345,7 +107369,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
           sqlite3VdbeAddOp3(v, OP_Eq, 8+j, addr+8, 3); VdbeCoverage(v);
           sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
           sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1);
-          sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pIdx->zName, P4_TRANSIENT);
+          sqlite3VdbeLoadString(v, 3, pIdx->zName);
           sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7);
           sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1);
         }
@@ -106353,9 +107377,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
       } 
     }
     addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
-    sqlite3VdbeChangeP3(v, addr, -mxErr);
-    sqlite3VdbeJumpHere(v, addr);
-    sqlite3VdbeChangeP4(v, addr+1, "ok", P4_STATIC);
+    sqlite3VdbeChangeP2(v, addr, -mxErr);
+    sqlite3VdbeJumpHere(v, addr+1);
+    sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC);
   }
   break;
 #endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@@ -106401,14 +107425,10 @@ SQLITE_PRIVATE void sqlite3Pragma(
     const struct EncName *pEnc;
     if( !zRight ){    /* "PRAGMA encoding" */
       if( sqlite3ReadSchema(pParse) ) goto pragma_out;
-      sqlite3VdbeSetNumCols(v, 1);
-      sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "encoding", SQLITE_STATIC);
-      sqlite3VdbeAddOp2(v, OP_String8, 0, 1);
       assert( encnames[SQLITE_UTF8].enc==SQLITE_UTF8 );
       assert( encnames[SQLITE_UTF16LE].enc==SQLITE_UTF16LE );
       assert( encnames[SQLITE_UTF16BE].enc==SQLITE_UTF16BE );
-      sqlite3VdbeChangeP4(v, -1, encnames[ENC(pParse->db)].zName, P4_STATIC);
-      sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
+      returnSingleText(v, "encoding", encnames[ENC(pParse->db)].zName);
     }else{                        /* "PRAGMA encoding = XXX" */
       /* Only change the value of sqlite.enc if the database handle is not
       ** initialized. If the main database exists, the new sqlite.enc value
@@ -106509,11 +107529,10 @@ SQLITE_PRIVATE void sqlite3Pragma(
   case PragTyp_COMPILE_OPTIONS: {
     int i = 0;
     const char *zOpt;
-    sqlite3VdbeSetNumCols(v, 1);
     pParse->nMem = 1;
-    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "compile_option", SQLITE_STATIC);
+    setOneColumnName(v, "compile_option");
     while( (zOpt = sqlite3_compileoption_get(i++))!=0 ){
-      sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, zOpt, 0);
+      sqlite3VdbeLoadString(v, 1, zOpt);
       sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
     }
   }
@@ -106527,6 +107546,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
   ** Checkpoint the database.
   */
   case PragTyp_WAL_CHECKPOINT: {
+    static const char *azCol[] = { "busy", "log", "checkpointed" };
     int iBt = (pId2->z?iDb:SQLITE_MAX_ATTACHED);
     int eMode = SQLITE_CHECKPOINT_PASSIVE;
     if( zRight ){
@@ -106538,12 +107558,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
         eMode = SQLITE_CHECKPOINT_TRUNCATE;
       }
     }
-    sqlite3VdbeSetNumCols(v, 3);
+    setAllColumnNames(v, 3, azCol);  assert( 3==ArraySize(azCol) );
     pParse->nMem = 3;
-    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "busy", SQLITE_STATIC);
-    sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "log", SQLITE_STATIC);
-    sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "checkpointed", SQLITE_STATIC);
-
     sqlite3VdbeAddOp3(v, OP_Checkpoint, iBt, eMode, 1);
     sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
   }
@@ -106561,7 +107577,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
     if( zRight ){
       sqlite3_wal_autocheckpoint(db, sqlite3Atoi(zRight));
     }
-    returnSingleInt(pParse, "wal_autocheckpoint", 
+    returnSingleInt(v, "wal_autocheckpoint", 
        db->xWalCallback==sqlite3WalDefaultHook ? 
            SQLITE_PTR_TO_INT(db->pWalArg) : 0);
   }
@@ -106594,7 +107610,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
     if( zRight ){
       sqlite3_busy_timeout(db, sqlite3Atoi(zRight));
     }
-    returnSingleInt(pParse, "timeout",  db->busyTimeout);
+    returnSingleInt(v, "timeout",  db->busyTimeout);
     break;
   }
 
@@ -106614,7 +107630,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
     if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){
       sqlite3_soft_heap_limit64(N);
     }
-    returnSingleInt(pParse, "soft_heap_limit",  sqlite3_soft_heap_limit64(-1));
+    returnSingleInt(v, "soft_heap_limit",  sqlite3_soft_heap_limit64(-1));
     break;
   }
 
@@ -106633,7 +107649,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
     ){
       sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, (int)(N&0x7fffffff));
     }
-    returnSingleInt(pParse, "threads",
+    returnSingleInt(v, "threads",
                     sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, -1));
     break;
   }
@@ -106646,17 +107662,15 @@ SQLITE_PRIVATE void sqlite3Pragma(
     static const char *const azLockName[] = {
       "unlocked", "shared", "reserved", "pending", "exclusive"
     };
+    static const char *azCol[] = { "database", "status" };
     int i;
-    sqlite3VdbeSetNumCols(v, 2);
+    setAllColumnNames(v, 2, azCol); assert( 2==ArraySize(azCol) );
     pParse->nMem = 2;
-    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "database", SQLITE_STATIC);
-    sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "status", SQLITE_STATIC);
     for(i=0; i<db->nDb; i++){
       Btree *pBt;
       const char *zState = "unknown";
       int j;
       if( db->aDb[i].zName==0 ) continue;
-      sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, db->aDb[i].zName, P4_STATIC);
       pBt = db->aDb[i].pBt;
       if( pBt==0 || sqlite3BtreePager(pBt)==0 ){
         zState = "closed";
@@ -106664,7 +107678,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
                                      SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){
          zState = azLockName[j];
       }
-      sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, zState, P4_STATIC);
+      sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zName, zState);
       sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
     }
     break;
@@ -108029,12 +109043,12 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
     int isOuter;
 
     if( NEVER(pLeftTab==0 || pRightTab==0) ) continue;
-    isOuter = (pRight->jointype & JT_OUTER)!=0;
+    isOuter = (pRight->fg.jointype & JT_OUTER)!=0;
 
     /* When the NATURAL keyword is present, add WHERE clause terms for
     ** every column that the two tables have in common.
     */
-    if( pRight->jointype & JT_NATURAL ){
+    if( pRight->fg.jointype & JT_NATURAL ){
       if( pRight->pOn || pRight->pUsing ){
         sqlite3ErrorMsg(pParse, "a NATURAL join may not have "
            "an ON or USING clause", 0);
@@ -108119,6 +109133,7 @@ static void pushOntoSorter(
   SortCtx *pSort,        /* Information about the ORDER BY clause */
   Select *pSelect,       /* The whole SELECT statement */
   int regData,           /* First register holding data to be sorted */
+  int regOrigData,       /* First register holding data before packing */
   int nData,             /* Number of elements in the data array */
   int nPrefixReg         /* No. of reg prior to regData available for use */
 ){
@@ -108132,6 +109147,7 @@ static void pushOntoSorter(
   int op;                            /* Opcode to add sorter record to sorter */
 
   assert( bSeq==0 || bSeq==1 );
+  assert( nData==1 || regData==regOrigData );
   if( nPrefixReg ){
     assert( nPrefixReg==nExpr+bSeq );
     regBase = regData - nExpr - bSeq;
@@ -108139,7 +109155,8 @@ static void pushOntoSorter(
     regBase = pParse->nMem + 1;
     pParse->nMem += nBase;
   }
-  sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, SQLITE_ECEL_DUP);
+  sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, regOrigData,
+                          SQLITE_ECEL_DUP|SQLITE_ECEL_REF);
   if( bSeq ){
     sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
   }
@@ -108199,7 +109216,7 @@ static void pushOntoSorter(
     }else{
       iLimit = pSelect->iLimit;
     }
-    addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, -1); VdbeCoverage(v);
+    addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, 1); VdbeCoverage(v);
     sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
     sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
     sqlite3VdbeJumpHere(v, addr);
@@ -108215,11 +109232,8 @@ static void codeOffset(
   int iContinue     /* Jump here to skip the current record */
 ){
   if( iOffset>0 ){
-    int addr;
-    addr = sqlite3VdbeAddOp3(v, OP_IfNeg, iOffset, 0, -1); VdbeCoverage(v);
-    sqlite3VdbeAddOp2(v, OP_Goto, 0, iContinue);
-    VdbeComment((v, "skip OFFSET records"));
-    sqlite3VdbeJumpHere(v, addr);
+    sqlite3VdbeAddOp3(v, OP_IfPos, iOffset, iContinue, 1); VdbeCoverage(v);
+    VdbeComment((v, "OFFSET"));
   }
 }
 
@@ -108349,7 +109363,7 @@ static void selectInnerLoop(
     }else{
       ecelFlags = 0;
     }
-    sqlite3ExprCodeExprList(pParse, pEList, regResult, ecelFlags);
+    sqlite3ExprCodeExprList(pParse, pEList, regResult, 0, ecelFlags);
   }
 
   /* If the DISTINCT keyword was present on the SELECT statement
@@ -108465,7 +109479,7 @@ static void selectInnerLoop(
       }
 #endif
       if( pSort ){
-        pushOntoSorter(pParse, pSort, p, r1+nPrefixReg, 1, nPrefixReg);
+        pushOntoSorter(pParse, pSort, p, r1+nPrefixReg,regResult,1,nPrefixReg);
       }else{
         int r2 = sqlite3GetTempReg(pParse);
         sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2);
@@ -108491,7 +109505,7 @@ static void selectInnerLoop(
         ** ORDER BY in this case since the order of entries in the set
         ** does not matter.  But there might be a LIMIT clause, in which
         ** case the order does matter */
-        pushOntoSorter(pParse, pSort, p, regResult, 1, nPrefixReg);
+        pushOntoSorter(pParse, pSort, p, regResult, regResult, 1, nPrefixReg);
       }else{
         int r1 = sqlite3GetTempReg(pParse);
         sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1);
@@ -108517,7 +109531,7 @@ static void selectInnerLoop(
     case SRT_Mem: {
       assert( nResultCol==1 );
       if( pSort ){
-        pushOntoSorter(pParse, pSort, p, regResult, 1, nPrefixReg);
+        pushOntoSorter(pParse, pSort, p, regResult, regResult, 1, nPrefixReg);
       }else{
         assert( regResult==iParm );
         /* The LIMIT clause will jump out of the loop for us */
@@ -108531,7 +109545,8 @@ static void selectInnerLoop(
       testcase( eDest==SRT_Coroutine );
       testcase( eDest==SRT_Output );
       if( pSort ){
-        pushOntoSorter(pParse, pSort, p, regResult, nResultCol, nPrefixReg);
+        pushOntoSorter(pParse, pSort, p, regResult, regResult, nResultCol,
+                       nPrefixReg);
       }else if( eDest==SRT_Coroutine ){
         sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
       }else{
@@ -108825,7 +109840,7 @@ static void generateSortTail(
 
   if( pSort->labelBkOut ){
     sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
-    sqlite3VdbeAddOp2(v, OP_Goto, 0, addrBreak);
+    sqlite3VdbeGoto(v, addrBreak);
     sqlite3VdbeResolveLabel(v, pSort->labelBkOut);
   }
   iTab = pSort->iECursor;
@@ -109210,7 +110225,7 @@ static void generateColumnNames(
 ** Return SQLITE_OK on success.  If a memory allocation error occurs,
 ** store NULL in *paCol and 0 in *pnCol and return SQLITE_NOMEM.
 */
-static int selectColumnsFromExprList(
+SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
   Parse *pParse,          /* Parsing context */
   ExprList *pEList,       /* Expr list from which to derive column names */
   i16 *pnCol,             /* Write the number of columns here */
@@ -109377,7 +110392,7 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
   pTab->nRef = 1;
   pTab->zName = 0;
   pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
-  selectColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
+  sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
   selectAddColumnTypeAndCollation(pParse, pTab, pSelect);
   pTab->iPKey = -1;
   if( db->mallocFailed ){
@@ -109434,7 +110449,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
   Vdbe *v = 0;
   int iLimit = 0;
   int iOffset;
-  int addr1, n;
+  int n;
   if( p->iLimit ) return;
 
   /* 
@@ -109453,7 +110468,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
       sqlite3VdbeAddOp2(v, OP_Integer, n, iLimit);
       VdbeComment((v, "LIMIT counter"));
       if( n==0 ){
-        sqlite3VdbeAddOp2(v, OP_Goto, 0, iBreak);
+        sqlite3VdbeGoto(v, iBreak);
       }else if( n>=0 && p->nSelectRow>(u64)n ){
         p->nSelectRow = n;
       }
@@ -109469,14 +110484,10 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
       sqlite3ExprCode(pParse, p->pOffset, iOffset);
       sqlite3VdbeAddOp1(v, OP_MustBeInt, iOffset); VdbeCoverage(v);
       VdbeComment((v, "OFFSET counter"));
-      addr1 = sqlite3VdbeAddOp1(v, OP_IfPos, iOffset); VdbeCoverage(v);
-      sqlite3VdbeAddOp2(v, OP_Integer, 0, iOffset);
-      sqlite3VdbeJumpHere(v, addr1);
+      sqlite3VdbeAddOp3(v, OP_SetIfNotPos, iOffset, iOffset, 0);
       sqlite3VdbeAddOp3(v, OP_Add, iLimit, iOffset, iOffset+1);
       VdbeComment((v, "LIMIT+OFFSET"));
-      addr1 = sqlite3VdbeAddOp1(v, OP_IfPos, iLimit); VdbeCoverage(v);
-      sqlite3VdbeAddOp2(v, OP_Integer, -1, iOffset+1);
-      sqlite3VdbeJumpHere(v, addr1);
+      sqlite3VdbeAddOp3(v, OP_SetIfNotPos, iLimit, iOffset+1, -1);
     }
   }
 }
@@ -109556,7 +110567,7 @@ static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){
 **
 **
 ** There is exactly one reference to the recursive-table in the FROM clause
-** of recursive-query, marked with the SrcList->a[].isRecursive flag.
+** of recursive-query, marked with the SrcList->a[].fg.isRecursive flag.
 **
 ** The setup-query runs once to generate an initial set of rows that go
 ** into a Queue table.  Rows are extracted from the Queue table one by
@@ -109621,7 +110632,7 @@ static void generateWithRecursiveQuery(
 
   /* Locate the cursor number of the Current table */
   for(i=0; ALWAYS(i<pSrc->nSrc); i++){
-    if( pSrc->a[i].isRecursive ){
+    if( pSrc->a[i].fg.isRecursive ){
       iCurrent = pSrc->a[i].iCursor;
       break;
     }
@@ -109701,7 +110712,7 @@ static void generateWithRecursiveQuery(
   }
 
   /* Keep running the loop until the Queue is empty */
-  sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop);
+  sqlite3VdbeGoto(v, addrTop);
   sqlite3VdbeResolveLabel(v, addrBreak);
 
 end_of_recursive_query:
@@ -109892,6 +110903,11 @@ static int multiSelect(
       if( p->iLimit ){
         addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v);
         VdbeComment((v, "Jump ahead if LIMIT reached"));
+        if( p->iOffset ){
+          sqlite3VdbeAddOp3(v, OP_SetIfNotPos, p->iOffset, p->iOffset, 0);
+          sqlite3VdbeAddOp3(v, OP_Add, p->iLimit, p->iOffset, p->iOffset+1);
+          sqlite3VdbeAddOp3(v, OP_SetIfNotPos, p->iLimit, p->iOffset+1, -1);
+        }
       }
       explainSetInteger(iSub2, pParse->iNextSelectId);
       rc = sqlite3Select(pParse, p, &dest);
@@ -110199,12 +111215,12 @@ static int generateOutputSubroutine(
   /* Suppress duplicates for UNION, EXCEPT, and INTERSECT 
   */
   if( regPrev ){
-    int j1, j2;
-    j1 = sqlite3VdbeAddOp1(v, OP_IfNot, regPrev); VdbeCoverage(v);
-    j2 = sqlite3VdbeAddOp4(v, OP_Compare, pIn->iSdst, regPrev+1, pIn->nSdst,
+    int addr1, addr2;
+    addr1 = sqlite3VdbeAddOp1(v, OP_IfNot, regPrev); VdbeCoverage(v);
+    addr2 = sqlite3VdbeAddOp4(v, OP_Compare, pIn->iSdst, regPrev+1, pIn->nSdst,
                               (char*)sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO);
-    sqlite3VdbeAddOp3(v, OP_Jump, j2+2, iContinue, j2+2); VdbeCoverage(v);
-    sqlite3VdbeJumpHere(v, j1);
+    sqlite3VdbeAddOp3(v, OP_Jump, addr2+2, iContinue, addr2+2); VdbeCoverage(v);
+    sqlite3VdbeJumpHere(v, addr1);
     sqlite3VdbeAddOp3(v, OP_Copy, pIn->iSdst, regPrev+1, pIn->nSdst-1);
     sqlite3VdbeAddOp2(v, OP_Integer, 1, regPrev);
   }
@@ -110421,7 +111437,7 @@ static int multiSelectOrderBy(
   int savedOffset;      /* Saved value of p->iOffset */
   int labelCmpr;        /* Label for the start of the merge algorithm */
   int labelEnd;         /* Label for the end of the overall SELECT stmt */
-  int j1;               /* Jump instructions that get retargetted */
+  int addr1;            /* Jump instructions that get retargetted */
   int op;               /* One of TK_ALL, TK_UNION, TK_EXCEPT, TK_INTERSECT */
   KeyInfo *pKeyDup = 0; /* Comparison information for duplicate removal */
   KeyInfo *pKeyMerge;   /* Comparison information for merging rows */
@@ -110557,19 +111573,19 @@ static int multiSelectOrderBy(
   ** left of the compound operator - the "A" select.
   */
   addrSelectA = sqlite3VdbeCurrentAddr(v) + 1;
-  j1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA);
+  addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA);
   VdbeComment((v, "left SELECT"));
   pPrior->iLimit = regLimitA;
   explainSetInteger(iSub1, pParse->iNextSelectId);
   sqlite3Select(pParse, pPrior, &destA);
   sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrA);
-  sqlite3VdbeJumpHere(v, j1);
+  sqlite3VdbeJumpHere(v, addr1);
 
   /* Generate a coroutine to evaluate the SELECT statement on 
   ** the right - the "B" select
   */
   addrSelectB = sqlite3VdbeCurrentAddr(v) + 1;
-  j1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB);
+  addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB);
   VdbeComment((v, "right SELECT"));
   savedLimit = p->iLimit;
   savedOffset = p->iOffset;
@@ -110610,7 +111626,7 @@ static int multiSelectOrderBy(
     addrEofA = sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
     addrEofA_noB = sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, labelEnd);
                                      VdbeCoverage(v);
-    sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEofA);
+    sqlite3VdbeGoto(v, addrEofA);
     p->nSelectRow += pPrior->nSelectRow;
   }
 
@@ -110624,7 +111640,7 @@ static int multiSelectOrderBy(
     VdbeNoopComment((v, "eof-B subroutine"));
     addrEofB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
     sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, labelEnd); VdbeCoverage(v);
-    sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEofB);
+    sqlite3VdbeGoto(v, addrEofB);
   }
 
   /* Generate code to handle the case of A<B
@@ -110632,7 +111648,7 @@ static int multiSelectOrderBy(
   VdbeNoopComment((v, "A-lt-B subroutine"));
   addrAltB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
   sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA); VdbeCoverage(v);
-  sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
+  sqlite3VdbeGoto(v, labelCmpr);
 
   /* Generate code to handle the case of A==B
   */
@@ -110645,7 +111661,7 @@ static int multiSelectOrderBy(
     VdbeNoopComment((v, "A-eq-B subroutine"));
     addrAeqB =
     sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA); VdbeCoverage(v);
-    sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
+    sqlite3VdbeGoto(v, labelCmpr);
   }
 
   /* Generate code to handle the case of A>B
@@ -110656,11 +111672,11 @@ static int multiSelectOrderBy(
     sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
   }
   sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); VdbeCoverage(v);
-  sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
+  sqlite3VdbeGoto(v, labelCmpr);
 
   /* This code runs once to initialize everything.
   */
-  sqlite3VdbeJumpHere(v, j1);
+  sqlite3VdbeJumpHere(v, addr1);
   sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA_noB); VdbeCoverage(v);
   sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); VdbeCoverage(v);
 
@@ -110703,7 +111719,7 @@ static int multiSelectOrderBy(
 #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
 /* Forward Declarations */
 static void substExprList(sqlite3*, ExprList*, int, ExprList*);
-static void substSelect(sqlite3*, Select *, int, ExprList *);
+static void substSelect(sqlite3*, Select *, int, ExprList*, int);
 
 /*
 ** Scan through the expression pExpr.  Replace every reference to
@@ -110740,7 +111756,7 @@ static Expr *substExpr(
     pExpr->pLeft = substExpr(db, pExpr->pLeft, iTable, pEList);
     pExpr->pRight = substExpr(db, pExpr->pRight, iTable, pEList);
     if( ExprHasProperty(pExpr, EP_xIsSelect) ){
-      substSelect(db, pExpr->x.pSelect, iTable, pEList);
+      substSelect(db, pExpr->x.pSelect, iTable, pEList, 1);
     }else{
       substExprList(db, pExpr->x.pList, iTable, pEList);
     }
@@ -110763,25 +111779,28 @@ static void substSelect(
   sqlite3 *db,         /* Report malloc errors here */
   Select *p,           /* SELECT statement in which to make substitutions */
   int iTable,          /* Table to be replaced */
-  ExprList *pEList     /* Substitute values */
+  ExprList *pEList,    /* Substitute values */
+  int doPrior          /* Do substitutes on p->pPrior too */
 ){
   SrcList *pSrc;
   struct SrcList_item *pItem;
   int i;
   if( !p ) return;
-  substExprList(db, p->pEList, iTable, pEList);
-  substExprList(db, p->pGroupBy, iTable, pEList);
-  substExprList(db, p->pOrderBy, iTable, pEList);
-  p->pHaving = substExpr(db, p->pHaving, iTable, pEList);
-  p->pWhere = substExpr(db, p->pWhere, iTable, pEList);
-  substSelect(db, p->pPrior, iTable, pEList);
-  pSrc = p->pSrc;
-  assert( pSrc );  /* Even for (SELECT 1) we have: pSrc!=0 but pSrc->nSrc==0 */
-  if( ALWAYS(pSrc) ){
+  do{
+    substExprList(db, p->pEList, iTable, pEList);
+    substExprList(db, p->pGroupBy, iTable, pEList);
+    substExprList(db, p->pOrderBy, iTable, pEList);
+    p->pHaving = substExpr(db, p->pHaving, iTable, pEList);
+    p->pWhere = substExpr(db, p->pWhere, iTable, pEList);
+    pSrc = p->pSrc;
+    assert( pSrc!=0 );
     for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
-      substSelect(db, pItem->pSelect, iTable, pEList);
+      substSelect(db, pItem->pSelect, iTable, pEList, 1);
+      if( pItem->fg.isTabFunc ){
+        substExprList(db, pItem->u1.pFuncArg, iTable, pEList);
+      }
     }
-  }
+  }while( doPrior && (p = p->pPrior)!=0 );
 }
 #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
 
@@ -110933,7 +111952,7 @@ static int flattenSubquery(
   int subqueryIsAgg    /* True if the subquery uses aggregate functions */
 ){
   const char *zSavedAuthContext = pParse->zAuthContext;
-  Select *pParent;
+  Select *pParent;    /* Current UNION ALL term of the other query */
   Select *pSub;       /* The inner query or "subquery" */
   Select *pSub1;      /* Pointer to the rightmost select in sub-query */
   SrcList *pSrc;      /* The FROM clause of the outer query */
@@ -111036,7 +112055,7 @@ static int flattenSubquery(
   ** is fraught with danger.  Best to avoid the whole thing.  If the
   ** subquery is the right term of a LEFT JOIN, then do not flatten.
   */
-  if( (pSubitem->jointype & JT_OUTER)!=0 ){
+  if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){
     return 0;
   }
 
@@ -111207,7 +112226,7 @@ static int flattenSubquery(
 
     if( pSrc ){
       assert( pParent==p );  /* First time through the loop */
-      jointype = pSubitem->jointype;
+      jointype = pSubitem->fg.jointype;
     }else{
       assert( pParent!=p );  /* 2nd and subsequent times through the loop */
       pSrc = pParent->pSrc = sqlite3SrcListAppend(db, 0, 0, 0);
@@ -111228,9 +112247,9 @@ static int flattenSubquery(
     **
     ** The outer query has 3 slots in its FROM clause.  One slot of the
     ** outer query (the middle slot) is used by the subquery.  The next
-    ** block of code will expand the out query to 4 slots.  The middle
-    ** slot is expanded to two slots in order to make space for the
-    ** two elements in the FROM clause of the subquery.
+    ** block of code will expand the outer query FROM clause to 4 slots.
+    ** The middle slot is expanded to two slots in order to make space
+    ** for the two elements in the FROM clause of the subquery.
     */
     if( nSubSrc>1 ){
       pParent->pSrc = pSrc = sqlite3SrcListEnlarge(db, pSrc, nSubSrc-1,iFrom+1);
@@ -111247,7 +112266,7 @@ static int flattenSubquery(
       pSrc->a[i+iFrom] = pSubSrc->a[i];
       memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
     }
-    pSrc->a[iFrom].jointype = jointype;
+    pSrc->a[iFrom].fg.jointype = jointype;
   
     /* Now begin substituting subquery result set expressions for 
     ** references to the iParent in the outer query.
@@ -111269,11 +112288,6 @@ static int flattenSubquery(
         pList->a[i].zName = zName;
       }
     }
-    substExprList(db, pParent->pEList, iParent, pSub->pEList);
-    if( isAgg ){
-      substExprList(db, pParent->pGroupBy, iParent, pSub->pEList);
-      pParent->pHaving = substExpr(db, pParent->pHaving, iParent, pSub->pEList);
-    }
     if( pSub->pOrderBy ){
       /* At this point, any non-zero iOrderByCol values indicate that the
       ** ORDER BY column expression is identical to the iOrderByCol'th
@@ -111293,27 +112307,20 @@ static int flattenSubquery(
       assert( pSub->pPrior==0 );
       pParent->pOrderBy = pOrderBy;
       pSub->pOrderBy = 0;
-    }else if( pParent->pOrderBy ){
-      substExprList(db, pParent->pOrderBy, iParent, pSub->pEList);
-    }
-    if( pSub->pWhere ){
-      pWhere = sqlite3ExprDup(db, pSub->pWhere, 0);
-    }else{
-      pWhere = 0;
     }
+    pWhere = sqlite3ExprDup(db, pSub->pWhere, 0);
     if( subqueryIsAgg ){
       assert( pParent->pHaving==0 );
       pParent->pHaving = pParent->pWhere;
       pParent->pWhere = pWhere;
-      pParent->pHaving = substExpr(db, pParent->pHaving, iParent, pSub->pEList);
       pParent->pHaving = sqlite3ExprAnd(db, pParent->pHaving, 
                                   sqlite3ExprDup(db, pSub->pHaving, 0));
       assert( pParent->pGroupBy==0 );
       pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0);
     }else{
-      pParent->pWhere = substExpr(db, pParent->pWhere, iParent, pSub->pEList);
       pParent->pWhere = sqlite3ExprAnd(db, pParent->pWhere, pWhere);
     }
+    substSelect(db, pParent, iParent, pSub->pEList, 0);
   
     /* The flattened query is distinct if either the inner or the
     ** outer query is distinct. 
@@ -111380,6 +112387,9 @@ static int flattenSubquery(
 **       enforces this restriction since this routine does not have enough
 **       information to know.)
 **
+**   (5) The WHERE clause expression originates in the ON or USING clause
+**       of a LEFT JOIN.
+**
 ** Return 0 if no changes are made and non-zero if one or more WHERE clause
 ** terms are duplicated into the subquery.
 */
@@ -111402,6 +112412,7 @@ static int pushDownWhereTerms(
     nChng += pushDownWhereTerms(db, pSubq, pWhere->pRight, iCursor);
     pWhere = pWhere->pLeft;
   }
+  if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction 5 */
   if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){
     nChng++;
     while( pSubq ){
@@ -111498,9 +112509,9 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
 ** pFrom->pIndex and return SQLITE_OK.
 */
 SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, struct SrcList_item *pFrom){
-  if( pFrom->pTab && pFrom->zIndexedBy ){
+  if( pFrom->pTab && pFrom->fg.isIndexedBy ){
     Table *pTab = pFrom->pTab;
-    char *zIndexedBy = pFrom->zIndexedBy;
+    char *zIndexedBy = pFrom->u1.zIndexedBy;
     Index *pIdx;
     for(pIdx=pTab->pIndex; 
         pIdx && sqlite3StrICmp(pIdx->zName, zIndexedBy); 
@@ -111511,7 +112522,7 @@ SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, struct SrcList_item *pF
       pParse->checkSchema = 1;
       return SQLITE_ERROR;
     }
-    pFrom->pIndex = pIdx;
+    pFrom->pIBIndex = pIdx;
   }
   return SQLITE_OK;
 }
@@ -111672,12 +112683,12 @@ static int withExpand(
     int bMayRecursive;            /* True if compound joined by UNION [ALL] */
     With *pSavedWith;             /* Initial value of pParse->pWith */
 
-    /* If pCte->zErr is non-NULL at this point, then this is an illegal
+    /* If pCte->zCteErr is non-NULL at this point, then this is an illegal
     ** recursive reference to CTE pCte. Leave an error in pParse and return
-    ** early. If pCte->zErr is NULL, then this is not a recursive reference.
+    ** early. If pCte->zCteErr is NULL, then this is not a recursive reference.
     ** In this case, proceed.  */
-    if( pCte->zErr ){
-      sqlite3ErrorMsg(pParse, pCte->zErr, pCte->zName);
+    if( pCte->zCteErr ){
+      sqlite3ErrorMsg(pParse, pCte->zCteErr, pCte->zName);
       return SQLITE_ERROR;
     }
 
@@ -111706,7 +112717,7 @@ static int withExpand(
          && 0==sqlite3StrICmp(pItem->zName, pCte->zName)
           ){
           pItem->pTab = pTab;
-          pItem->isRecursive = 1;
+          pItem->fg.isRecursive = 1;
           pTab->nRef++;
           pSel->selFlags |= SF_Recursive;
         }
@@ -111722,7 +112733,7 @@ static int withExpand(
     }
     assert( pTab->nRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nRef==2 ));
 
-    pCte->zErr = "circular reference: %s";
+    pCte->zCteErr = "circular reference: %s";
     pSavedWith = pParse->pWith;
     pParse->pWith = pWith;
     sqlite3WalkSelect(pWalker, bMayRecursive ? pSel->pPrior : pSel);
@@ -111740,16 +112751,16 @@ static int withExpand(
       pEList = pCte->pCols;
     }
 
-    selectColumnsFromExprList(pParse, pEList, &pTab->nCol, &pTab->aCol);
+    sqlite3ColumnsFromExprList(pParse, pEList, &pTab->nCol, &pTab->aCol);
     if( bMayRecursive ){
       if( pSel->selFlags & SF_Recursive ){
-        pCte->zErr = "multiple recursive references: %s";
+        pCte->zCteErr = "multiple recursive references: %s";
       }else{
-        pCte->zErr = "recursive reference in a subquery: %s";
+        pCte->zCteErr = "recursive reference in a subquery: %s";
       }
       sqlite3WalkSelect(pWalker, pSel);
     }
-    pCte->zErr = 0;
+    pCte->zCteErr = 0;
     pParse->pWith = pSavedWith;
   }
 
@@ -111836,17 +112847,9 @@ static int selectExpander(Walker *pWalker, Select *p){
   */
   for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
     Table *pTab;
-    assert( pFrom->isRecursive==0 || pFrom->pTab );
-    if( pFrom->isRecursive ) continue;
-    if( pFrom->pTab!=0 ){
-      /* This statement has already been prepared.  There is no need
-      ** to go further. */
-      assert( i==0 );
-#ifndef SQLITE_OMIT_CTE
-      selectPopWith(pWalker, p);
-#endif
-      return WRC_Prune;
-    }
+    assert( pFrom->fg.isRecursive==0 || pFrom->pTab!=0 );
+    if( pFrom->fg.isRecursive ) continue;
+    assert( pFrom->pTab==0 );
 #ifndef SQLITE_OMIT_CTE
     if( withExpand(pWalker, pFrom) ) return WRC_Abort;
     if( pFrom->pTab ) {} else
@@ -111863,7 +112866,7 @@ static int selectExpander(Walker *pWalker, Select *p){
       pTab->nRef = 1;
       pTab->zName = sqlite3MPrintf(db, "sqlite_sq_%p", (void*)pTab);
       while( pSel->pPrior ){ pSel = pSel->pPrior; }
-      selectColumnsFromExprList(pParse, pSel->pEList, &pTab->nCol, &pTab->aCol);
+      sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol);
       pTab->iPKey = -1;
       pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
       pTab->tabFlags |= TF_Ephemeral;
@@ -111882,12 +112885,19 @@ static int selectExpander(Walker *pWalker, Select *p){
       pTab->nRef++;
 #if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE)
       if( pTab->pSelect || IsVirtual(pTab) ){
-        /* We reach here if the named table is a really a view */
+        i16 nCol;
         if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
         assert( pFrom->pSelect==0 );
+        if( pFrom->fg.isTabFunc && !IsVirtual(pTab) ){
+          sqlite3ErrorMsg(pParse, "'%s' is not a function", pTab->zName);
+          return WRC_Abort;
+        }
         pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
         sqlite3SelectSetName(pFrom->pSelect, pTab->zName);
+        nCol = pTab->nCol;
+        pTab->nCol = -1;
         sqlite3WalkSelect(pWalker, pFrom->pSelect);
+        pTab->nCol = nCol;
       }
 #endif
     }
@@ -112000,7 +113010,7 @@ static int selectExpander(Walker *pWalker, Select *p){
             tableSeen = 1;
 
             if( i>0 && zTName==0 ){
-              if( (pFrom->jointype & JT_NATURAL)!=0
+              if( (pFrom->fg.jointype & JT_NATURAL)!=0
                 && tableAndColumnIndex(pTabList, i, zName, 0, 0)
               ){
                 /* In a NATURAL join, omit the join columns from the 
@@ -112135,19 +113145,19 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
   struct SrcList_item *pFrom;
 
   assert( p->selFlags & SF_Resolved );
-  if( (p->selFlags & SF_HasTypeInfo)==0 ){
-    p->selFlags |= SF_HasTypeInfo;
-    pParse = pWalker->pParse;
-    pTabList = p->pSrc;
-    for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
-      Table *pTab = pFrom->pTab;
-      if( ALWAYS(pTab!=0) && (pTab->tabFlags & TF_Ephemeral)!=0 ){
-        /* A sub-query in the FROM clause of a SELECT */
-        Select *pSel = pFrom->pSelect;
-        if( pSel ){
-          while( pSel->pPrior ) pSel = pSel->pPrior;
-          selectAddColumnTypeAndCollation(pParse, pTab, pSel);
-        }
+  assert( (p->selFlags & SF_HasTypeInfo)==0 );
+  p->selFlags |= SF_HasTypeInfo;
+  pParse = pWalker->pParse;
+  pTabList = p->pSrc;
+  for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
+    Table *pTab = pFrom->pTab;
+    assert( pTab!=0 );
+    if( (pTab->tabFlags & TF_Ephemeral)!=0 ){
+      /* A sub-query in the FROM clause of a SELECT */
+      Select *pSel = pFrom->pSelect;
+      if( pSel ){
+        while( pSel->pPrior ) pSel = pSel->pPrior;
+        selectAddColumnTypeAndCollation(pParse, pTab, pSel);
       }
     }
   }
@@ -112286,7 +113296,7 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
     if( pList ){
       nArg = pList->nExpr;
       regAgg = sqlite3GetTempRange(pParse, nArg);
-      sqlite3ExprCodeExprList(pParse, pList, regAgg, SQLITE_ECEL_DUP);
+      sqlite3ExprCodeExprList(pParse, pList, regAgg, 0, SQLITE_ECEL_DUP);
     }else{
       nArg = 0;
       regAgg = 0;
@@ -112473,7 +113483,17 @@ SQLITE_PRIVATE int sqlite3Select(
     struct SrcList_item *pItem = &pTabList->a[i];
     Select *pSub = pItem->pSelect;
     int isAggSub;
+    Table *pTab = pItem->pTab;
     if( pSub==0 ) continue;
+
+    /* Catch mismatch in the declared columns of a view and the number of
+    ** columns in the SELECT on the RHS */
+    if( pTab->nCol!=pSub->pEList->nExpr ){
+      sqlite3ErrorMsg(pParse, "expected %d columns for '%s' but got %d",
+                      pTab->nCol, pTab->zName, pSub->pEList->nExpr);
+      goto select_end;
+    }
+
     isAggSub = (pSub->selFlags & SF_Aggregate)!=0;
     if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){
       /* This subquery can be absorbed into its parent. */
@@ -112527,7 +113547,7 @@ SQLITE_PRIVATE int sqlite3Select(
     ** is sufficient, though the subroutine to manifest the view does need
     ** to be invoked again. */
     if( pItem->addrFillSub ){
-      if( pItem->viaCoroutine==0 ){
+      if( pItem->fg.viaCoroutine==0 ){
         sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub);
       }
       continue;
@@ -112545,7 +113565,7 @@ SQLITE_PRIVATE int sqlite3Select(
     /* Make copies of constant WHERE-clause terms in the outer query down
     ** inside the subquery.  This can help the subquery to run more efficiently.
     */
-    if( (pItem->jointype & JT_OUTER)==0
+    if( (pItem->fg.jointype & JT_OUTER)==0
      && pushDownWhereTerms(db, pSub, p->pWhere, pItem->iCursor)
     ){
 #if SELECTTRACE_ENABLED
@@ -112574,7 +113594,7 @@ SQLITE_PRIVATE int sqlite3Select(
       explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
       sqlite3Select(pParse, pSub, &dest);
       pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
-      pItem->viaCoroutine = 1;
+      pItem->fg.viaCoroutine = 1;
       pItem->regResult = dest.iSdst;
       sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn);
       sqlite3VdbeJumpHere(v, addrTop-1);
@@ -112592,7 +113612,7 @@ SQLITE_PRIVATE int sqlite3Select(
       pItem->regReturn = ++pParse->nMem;
       topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
       pItem->addrFillSub = topAddr+1;
-      if( pItem->isCorrelated==0 ){
+      if( pItem->fg.isCorrelated==0 ){
         /* If the subquery is not correlated and if we are not inside of
         ** a trigger, then we only need to compute the value of the subquery
         ** once. */
@@ -112690,7 +113710,7 @@ SQLITE_PRIVATE int sqlite3Select(
   p->nSelectRow = LARGEST_INT64;
   computeLimitRegisters(pParse, p, iEnd);
   if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
-    sqlite3VdbeGetOp(v, sSort.addrSortIndex)->opcode = OP_SorterOpen;
+    sqlite3VdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen);
     sSort.sortFlags |= SORTFLAG_UseSorter;
   }
 
@@ -112825,7 +113845,7 @@ SQLITE_PRIVATE int sqlite3Select(
     */
     if( pGroupBy ){
       KeyInfo *pKeyInfo;  /* Keying information for the group by clause */
-      int j1;             /* A-vs-B comparision jump */
+      int addr1;          /* A-vs-B comparision jump */
       int addrOutputRow;  /* Start of subroutine that outputs a result row */
       int regOutputRow;   /* Return address register for output subroutine */
       int addrSetAbort;   /* Set the abort flag and return */
@@ -112906,7 +113926,7 @@ SQLITE_PRIVATE int sqlite3Select(
         }
         regBase = sqlite3GetTempRange(pParse, nCol);
         sqlite3ExprCacheClear(pParse);
-        sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0);
+        sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0);
         j = nGroupBy;
         for(i=0; i<sAggInfo.nColumn; i++){
           struct AggInfo_col *pCol = &sAggInfo.aCol[i];
@@ -112973,8 +113993,8 @@ SQLITE_PRIVATE int sqlite3Select(
       }
       sqlite3VdbeAddOp4(v, OP_Compare, iAMem, iBMem, pGroupBy->nExpr,
                           (char*)sqlite3KeyInfoRef(pKeyInfo), P4_KEYINFO);
-      j1 = sqlite3VdbeCurrentAddr(v);
-      sqlite3VdbeAddOp3(v, OP_Jump, j1+1, 0, j1+1); VdbeCoverage(v);
+      addr1 = sqlite3VdbeCurrentAddr(v);
+      sqlite3VdbeAddOp3(v, OP_Jump, addr1+1, 0, addr1+1); VdbeCoverage(v);
 
       /* Generate code that runs whenever the GROUP BY changes.
       ** Changes in the GROUP BY are detected by the previous code
@@ -112996,7 +114016,7 @@ SQLITE_PRIVATE int sqlite3Select(
       /* Update the aggregate accumulators based on the content of
       ** the current row
       */
-      sqlite3VdbeJumpHere(v, j1);
+      sqlite3VdbeJumpHere(v, addr1);
       updateAccumulator(pParse, &sAggInfo);
       sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag);
       VdbeComment((v, "indicate data in accumulator"));
@@ -113018,7 +114038,7 @@ SQLITE_PRIVATE int sqlite3Select(
 
       /* Jump over the subroutines
       */
-      sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEnd);
+      sqlite3VdbeGoto(v, addrEnd);
 
       /* Generate a subroutine that outputs a single row of the result
       ** set.  This subroutine first looks at the iUseFlag.  If iUseFlag
@@ -113172,7 +114192,7 @@ SQLITE_PRIVATE int sqlite3Select(
         updateAccumulator(pParse, &sAggInfo);
         assert( pMinMax==0 || pMinMax->nExpr==1 );
         if( sqlite3WhereIsOrdered(pWInfo)>0 ){
-          sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3WhereBreakLabel(pWInfo));
+          sqlite3VdbeGoto(v, sqlite3WhereBreakLabel(pWInfo));
           VdbeComment((v, "%s() by index",
                 (flag==WHERE_ORDERBY_MIN?"min":"max")));
         }
@@ -114695,9 +115715,9 @@ SQLITE_PRIVATE void sqlite3Update(
 
   /* Register Allocations */
   int regRowCount = 0;   /* A count of rows changed */
-  int regOldRowid;       /* The old rowid */
-  int regNewRowid;       /* The new rowid */
-  int regNew;            /* Content of the NEW.* table in triggers */
+  int regOldRowid = 0;   /* The old rowid */
+  int regNewRowid = 0;   /* The new rowid */
+  int regNew = 0;        /* Content of the NEW.* table in triggers */
   int regOld = 0;        /* Content of OLD.* table in triggers */
   int regRowSet = 0;     /* Rowset of rows to be updated */
   int regKey = 0;        /* composite PRIMARY KEY value */
@@ -114833,7 +115853,9 @@ SQLITE_PRIVATE void sqlite3Update(
 
   /* There is one entry in the aRegIdx[] array for each index on the table
   ** being updated.  Fill in aRegIdx[] with a register number that will hold
-  ** the key for accessing each index.  
+  ** the key for accessing each index.
+  **
+  ** FIXME:  Be smarter about omitting indexes that use expressions.
   */
   for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
     int reg;
@@ -114842,7 +115864,8 @@ SQLITE_PRIVATE void sqlite3Update(
     }else{
       reg = 0;
       for(i=0; i<pIdx->nKeyCol; i++){
-        if( aXRef[pIdx->aiColumn[i]]>=0 ){
+        i16 iIdxCol = pIdx->aiColumn[i];
+        if( iIdxCol<0 || aXRef[iIdxCol]>=0 ){
           reg = ++pParse->nMem;
           break;
         }
@@ -114858,29 +115881,20 @@ SQLITE_PRIVATE void sqlite3Update(
   if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
   sqlite3BeginWriteOperation(pParse, 1, iDb);
 
-#ifndef SQLITE_OMIT_VIRTUALTABLE
-  /* Virtual tables must be handled separately */
-  if( IsVirtual(pTab) ){
-    updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef,
-                       pWhere, onError);
-    pWhere = 0;
-    pTabList = 0;
-    goto update_cleanup;
-  }
-#endif
-
   /* Allocate required registers. */
-  regRowSet = ++pParse->nMem;
-  regOldRowid = regNewRowid = ++pParse->nMem;
-  if( chngPk || pTrigger || hasFK ){
-    regOld = pParse->nMem + 1;
+  if( !IsVirtual(pTab) ){
+    regRowSet = ++pParse->nMem;
+    regOldRowid = regNewRowid = ++pParse->nMem;
+    if( chngPk || pTrigger || hasFK ){
+      regOld = pParse->nMem + 1;
+      pParse->nMem += pTab->nCol;
+    }
+    if( chngKey || pTrigger || hasFK ){
+      regNewRowid = ++pParse->nMem;
+    }
+    regNew = pParse->nMem + 1;
     pParse->nMem += pTab->nCol;
   }
-  if( chngKey || pTrigger || hasFK ){
-    regNewRowid = ++pParse->nMem;
-  }
-  regNew = pParse->nMem + 1;
-  pParse->nMem += pTab->nCol;
 
   /* Start the view context. */
   if( isView ){
@@ -114903,6 +115917,15 @@ SQLITE_PRIVATE void sqlite3Update(
     goto update_cleanup;
   }
 
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+  /* Virtual tables must be handled separately */
+  if( IsVirtual(pTab) ){
+    updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef,
+                       pWhere, onError);
+    goto update_cleanup;
+  }
+#endif
+
   /* Begin the database scan
   */
   if( HasRowid(pTab) ){
@@ -114942,6 +115965,7 @@ SQLITE_PRIVATE void sqlite3Update(
     if( pWInfo==0 ) goto update_cleanup;
     okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
     for(i=0; i<nPk; i++){
+      assert( pPk->aiColumn[i]>=0 );
       sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pPk->aiColumn[i],
                                       iPk+i);
     }
@@ -114951,7 +115975,7 @@ SQLITE_PRIVATE void sqlite3Update(
       regKey = iPk;
     }else{
       sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey,
-                        sqlite3IndexAffinityStr(v, pPk), nPk);
+                        sqlite3IndexAffinityStr(db, pPk), nPk);
       sqlite3VdbeAddOp2(v, OP_IdxInsert, iEph, regKey);
     }
     sqlite3WhereEnd(pWInfo);
@@ -115064,7 +116088,6 @@ SQLITE_PRIVATE void sqlite3Update(
   newmask = sqlite3TriggerColmask(
       pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError
   );
-  /*sqlite3VdbeAddOp3(v, OP_Null, 0, regNew, regNew+pTab->nCol-1);*/
   for(i=0; i<pTab->nCol; i++){
     if( i==pTab->iPKey ){
       sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i);
@@ -115122,7 +116145,7 @@ SQLITE_PRIVATE void sqlite3Update(
   }
 
   if( !isView ){
-    int j1 = 0;           /* Address of jump instruction */
+    int addr1 = 0;        /* Address of jump instruction */
     int bReplace = 0;     /* True if REPLACE conflict resolution might happen */
 
     /* Do constraint checks. */
@@ -115138,20 +116161,20 @@ SQLITE_PRIVATE void sqlite3Update(
     /* Delete the index entries associated with the current record.  */
     if( bReplace || chngKey ){
       if( pPk ){
-        j1 = sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, 0, regKey, nKey);
+        addr1 = sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, 0, regKey, nKey);
       }else{
-        j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, 0, regOldRowid);
+        addr1 = sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, 0, regOldRowid);
       }
       VdbeCoverageNeverTaken(v);
     }
-    sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx);
+    sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx, -1);
   
     /* If changing the record number, delete the old record.  */
     if( hasFK || chngKey || pPk!=0 ){
       sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, 0);
     }
     if( bReplace || chngKey ){
-      sqlite3VdbeJumpHere(v, j1);
+      sqlite3VdbeJumpHere(v, addr1);
     }
 
     if( hasFK ){
@@ -115188,7 +116211,7 @@ SQLITE_PRIVATE void sqlite3Update(
     sqlite3VdbeResolveLabel(v, labelContinue);
     sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); VdbeCoverage(v);
   }else{
-    sqlite3VdbeAddOp2(v, OP_Goto, 0, labelContinue);
+    sqlite3VdbeGoto(v, labelContinue);
   }
   sqlite3VdbeResolveLabel(v, labelBreak);
 
@@ -115242,21 +116265,23 @@ update_cleanup:
 /*
 ** Generate code for an UPDATE of a virtual table.
 **
-** The strategy is that we create an ephemeral table that contains
+** There are two possible strategies - the default and the special 
+** "onepass" strategy. Onepass is only used if the virtual table 
+** implementation indicates that pWhere may match at most one row.
+**
+** The default strategy is to create an ephemeral table that contains
 ** for each row to be changed:
 **
 **   (A)  The original rowid of that row.
-**   (B)  The revised rowid for the row. (note1)
+**   (B)  The revised rowid for the row.
 **   (C)  The content of every column in the row.
 **
-** Then we loop over this ephemeral table and for each row in
-** the ephemeral table call VUpdate.
+** Then loop through the contents of this ephemeral table executing a
+** VUpdate for each row. When finished, drop the ephemeral table.
 **
-** When finished, drop the ephemeral table.
-**
-** (note1) Actually, if we know in advance that (A) is always the same
-** as (B) we only store (A), then duplicate (A) when pulling
-** it out of the ephemeral table before calling VUpdate.
+** The "onepass" strategy does not use an ephemeral table. Instead, it
+** stores the same values (A, B and C above) in a register array and
+** makes a single invocation of VUpdate.
 */
 static void updateVirtualTable(
   Parse *pParse,       /* The parsing context */
@@ -115269,66 +116294,96 @@ static void updateVirtualTable(
   int onError          /* ON CONFLICT strategy */
 ){
   Vdbe *v = pParse->pVdbe;  /* Virtual machine under construction */
-  ExprList *pEList = 0;     /* The result set of the SELECT statement */
-  Select *pSelect = 0;      /* The SELECT statement */
-  Expr *pExpr;              /* Temporary expression */
   int ephemTab;             /* Table holding the result of the SELECT */
   int i;                    /* Loop counter */
-  int addr;                 /* Address of top of loop */
-  int iReg;                 /* First register in set passed to OP_VUpdate */
   sqlite3 *db = pParse->db; /* Database connection */
   const char *pVTab = (const char*)sqlite3GetVTable(db, pTab);
-  SelectDest dest;
-
-  /* Construct the SELECT statement that will find the new values for
-  ** all updated rows. 
-  */
-  pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ID, "_rowid_"));
+  WhereInfo *pWInfo;
+  int nArg = 2 + pTab->nCol;      /* Number of arguments to VUpdate */
+  int regArg;                     /* First register in VUpdate arg array */
+  int regRec;                     /* Register in which to assemble record */
+  int regRowid;                   /* Register for ephem table rowid */
+  int iCsr = pSrc->a[0].iCursor;  /* Cursor used for virtual table scan */
+  int aDummy[2];                  /* Unused arg for sqlite3WhereOkOnePass() */
+  int bOnePass;                   /* True to use onepass strategy */
+  int addr;                       /* Address of OP_OpenEphemeral */
+
+  /* Allocate nArg registers to martial the arguments to VUpdate. Then
+  ** create and open the ephemeral table in which the records created from
+  ** these arguments will be temporarily stored. */
+  assert( v );
+  ephemTab = pParse->nTab++;
+  addr= sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, nArg);
+  regArg = pParse->nMem + 1;
+  pParse->nMem += nArg;
+  regRec = ++pParse->nMem;
+  regRowid = ++pParse->nMem;
+
+  /* Start scanning the virtual table */
+  pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0,0,WHERE_ONEPASS_DESIRED,0);
+  if( pWInfo==0 ) return;
+
+  /* Populate the argument registers. */
+  sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
   if( pRowid ){
-    pEList = sqlite3ExprListAppend(pParse, pEList,
-                                   sqlite3ExprDup(db, pRowid, 0));
+    sqlite3ExprCode(pParse, pRowid, regArg+1);
+  }else{
+    sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
   }
-  assert( pTab->iPKey<0 );
   for(i=0; i<pTab->nCol; i++){
     if( aXRef[i]>=0 ){
-      pExpr = sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr, 0);
+      sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
     }else{
-      pExpr = sqlite3Expr(db, TK_ID, pTab->aCol[i].zName);
+      sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i);
     }
-    pEList = sqlite3ExprListAppend(pParse, pEList, pExpr);
   }
-  pSelect = sqlite3SelectNew(pParse, pEList, pSrc, pWhere, 0, 0, 0, 0, 0, 0);
-  
-  /* Create the ephemeral table into which the update results will
-  ** be stored.
-  */
-  assert( v );
-  ephemTab = pParse->nTab++;
 
-  /* fill the ephemeral table 
-  */
-  sqlite3SelectDestInit(&dest, SRT_EphemTab, ephemTab);
-  sqlite3Select(pParse, pSelect, &dest);
+  bOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);
 
-  /* Generate code to scan the ephemeral table and call VUpdate. */
-  iReg = ++pParse->nMem;
-  pParse->nMem += pTab->nCol+1;
-  addr = sqlite3VdbeAddOp2(v, OP_Rewind, ephemTab, 0); VdbeCoverage(v);
-  sqlite3VdbeAddOp3(v, OP_Column,  ephemTab, 0, iReg);
-  sqlite3VdbeAddOp3(v, OP_Column, ephemTab, (pRowid?1:0), iReg+1);
-  for(i=0; i<pTab->nCol; i++){
-    sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i+1+(pRowid!=0), iReg+2+i);
+  if( bOnePass ){
+    /* If using the onepass strategy, no-op out the OP_OpenEphemeral coded
+    ** above. Also, if this is a top-level parse (not a trigger), clear the
+    ** multi-write flag so that the VM does not open a statement journal */
+    sqlite3VdbeChangeToNoop(v, addr);
+    if( sqlite3IsToplevel(pParse) ){
+      pParse->isMultiWrite = 0;
+    }
+  }else{
+    /* Create a record from the argument register contents and insert it into
+    ** the ephemeral table. */
+    sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec);
+    sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid);
+    sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid);
+  }
+
+
+  if( bOnePass==0 ){
+    /* End the virtual table scan */
+    sqlite3WhereEnd(pWInfo);
+
+    /* Begin scannning through the ephemeral table. */
+    addr = sqlite3VdbeAddOp1(v, OP_Rewind, ephemTab); VdbeCoverage(v);
+
+    /* Extract arguments from the current row of the ephemeral table and 
+    ** invoke the VUpdate method.  */
+    for(i=0; i<nArg; i++){
+      sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i, regArg+i);
+    }
   }
   sqlite3VtabMakeWritable(pParse, pTab);
-  sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, iReg, pVTab, P4_VTAB);
+  sqlite3VdbeAddOp4(v, OP_VUpdate, 0, nArg, regArg, pVTab, P4_VTAB);
   sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError);
   sqlite3MayAbort(pParse);
-  sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1); VdbeCoverage(v);
-  sqlite3VdbeJumpHere(v, addr);
-  sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);
 
-  /* Cleanup */
-  sqlite3SelectDelete(db, pSelect);  
+  /* End of the ephemeral table scan. Or, if using the onepass strategy,
+  ** jump to here if the scan visited zero rows. */
+  if( bOnePass==0 ){
+    sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1); VdbeCoverage(v);
+    sqlite3VdbeJumpHere(v, addr);
+    sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);
+  }else{
+    sqlite3WhereEnd(pWInfo);
+  }
 }
 #endif /* SQLITE_OMIT_VIRTUALTABLE */
 
@@ -115770,6 +116825,7 @@ static int createModule(
       pMod->pModule = pModule;
       pMod->pAux = pAux;
       pMod->xDestroy = xDestroy;
+      pMod->pEpoTab = 0;
       pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod);
       assert( pDel==0 || pDel==pMod );
       if( pDel ){
@@ -115997,23 +117053,17 @@ SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table *p){
 ** deleted.
 */
 static void addModuleArgument(sqlite3 *db, Table *pTable, char *zArg){
-  int i = pTable->nModuleArg++;
-  int nBytes = sizeof(char *)*(1+pTable->nModuleArg);
+  int nBytes = sizeof(char *)*(2+pTable->nModuleArg);
   char **azModuleArg;
   azModuleArg = sqlite3DbRealloc(db, pTable->azModuleArg, nBytes);
   if( azModuleArg==0 ){
-    int j;
-    for(j=0; j<i; j++){
-      sqlite3DbFree(db, pTable->azModuleArg[j]);
-    }
     sqlite3DbFree(db, zArg);
-    sqlite3DbFree(db, pTable->azModuleArg);
-    pTable->nModuleArg = 0;
   }else{
+    int i = pTable->nModuleArg++;
     azModuleArg[i] = zArg;
     azModuleArg[i+1] = 0;
+    pTable->azModuleArg = azModuleArg;
   }
-  pTable->azModuleArg = azModuleArg;
 }
 
 /*
@@ -116140,7 +117190,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
     sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
 
     iReg = ++pParse->nMem;
-    sqlite3VdbeAddOp4(v, OP_String8, 0, iReg, 0, pTab->zName, 0);
+    sqlite3VdbeLoadString(v, iReg, pTab->zName);
     sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg);
   }
 
@@ -116416,7 +117466,7 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab,
   ** invoke it now. If the module has not been registered, return an 
   ** error. Otherwise, do nothing.
   */
-  if( !pMod ){
+  if( pMod==0 || pMod->pModule->xCreate==0 || pMod->pModule->xDestroy==0 ){
     *pzErr = sqlite3MPrintf(db, "no such module: %s", zMod);
     rc = SQLITE_ERROR;
   }else{
@@ -116518,6 +117568,7 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab
   pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
   if( ALWAYS(pTab!=0 && pTab->pVTable!=0) ){
     VTable *p;
+    int (*xDestroy)(sqlite3_vtab *);
     for(p=pTab->pVTable; p; p=p->pNext){
       assert( p->pVtab );
       if( p->pVtab->nRef>0 ){
@@ -116525,7 +117576,9 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab
       }
     }
     p = vtabDisconnectAll(db, pTab);
-    rc = p->pMod->pModule->xDestroy(p->pVtab);
+    xDestroy = p->pMod->pModule->xDestroy;
+    assert( xDestroy!=0 );  /* Checked before the virtual table is created */
+    rc = xDestroy(p->pVtab);
     /* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */
     if( rc==SQLITE_OK ){
       assert( pTab->pVTable==p && p->pNext==0 );
@@ -116651,7 +117704,9 @@ SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){
     if( rc==SQLITE_OK ){
       rc = pModule->xBegin(pVTab->pVtab);
       if( rc==SQLITE_OK ){
+        int iSvpt = db->nStatement + db->nSavepoint;
         addToVTrans(db, pVTab);
+        if( iSvpt ) rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, iSvpt-1);
       }
     }
   }
@@ -116804,6 +117859,67 @@ SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
   }
 }
 
+/*
+** Check to see if virtual tale module pMod can be have an eponymous
+** virtual table instance.  If it can, create one if one does not already
+** exist. Return non-zero if the eponymous virtual table instance exists
+** when this routine returns, and return zero if it does not exist.
+**
+** An eponymous virtual table instance is one that is named after its
+** module, and more importantly, does not require a CREATE VIRTUAL TABLE
+** statement in order to come into existance.  Eponymous virtual table
+** instances always exist.  They cannot be DROP-ed.
+**
+** Any virtual table module for which xConnect and xCreate are the same
+** method can have an eponymous virtual table instance.
+*/
+SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){
+  const sqlite3_module *pModule = pMod->pModule;
+  Table *pTab;
+  char *zErr = 0;
+  int nName;
+  int rc;
+  sqlite3 *db = pParse->db;
+  if( pMod->pEpoTab ) return 1;
+  if( pModule->xCreate!=0 && pModule->xCreate!=pModule->xConnect ) return 0;
+  nName = sqlite3Strlen30(pMod->zName) + 1;
+  pTab = sqlite3DbMallocZero(db, sizeof(Table) + nName);
+  if( pTab==0 ) return 0;
+  pMod->pEpoTab = pTab;
+  pTab->zName = (char*)&pTab[1];
+  memcpy(pTab->zName, pMod->zName, nName);
+  pTab->nRef = 1;
+  pTab->pSchema = db->aDb[0].pSchema;
+  pTab->tabFlags |= TF_Virtual;
+  pTab->nModuleArg = 0;
+  pTab->iPKey = -1;
+  addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName));
+  addModuleArgument(db, pTab, 0);
+  addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName));
+  rc = vtabCallConstructor(db, pTab, pMod, pModule->xConnect, &zErr);
+  if( rc ){
+    sqlite3ErrorMsg(pParse, "%s", zErr);
+    sqlite3DbFree(db, zErr);
+    sqlite3VtabEponymousTableClear(db, pMod);
+    return 0;
+  }
+  return 1;
+}
+
+/*
+** Erase the eponymous virtual table instance associated with
+** virtual table module pMod, if it exists.
+*/
+SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){
+  Table *pTab = pMod->pEpoTab;
+  if( pTab!=0 ){
+    sqlite3DeleteColumnNames(db, pTab);
+    sqlite3VtabClear(db, pTab);
+    sqlite3DbFree(db, pTab);
+    pMod->pEpoTab = 0;
+  }
+}
+
 /*
 ** Return the ON CONFLICT resolution mode in effect for the virtual
 ** table update operation currently in progress.
@@ -117174,12 +118290,14 @@ struct WhereScan {
   WhereClause *pOrigWC;      /* Original, innermost WhereClause */
   WhereClause *pWC;          /* WhereClause currently being scanned */
   char *zCollName;           /* Required collating sequence, if not NULL */
+  Expr *pIdxExpr;            /* Search for this index expression */
   char idxaff;               /* Must match this affinity, if zCollName!=NULL */
   unsigned char nEquiv;      /* Number of entries in aEquiv[] */
   unsigned char iEquiv;      /* Next unused slot in aEquiv[] */
   u32 opMask;                /* Acceptable operators */
   int k;                     /* Resume scanning at this->pWC->a[this->k] */
-  int aEquiv[22];            /* Cursor,Column pairs for equivalence classes */
+  int aiCur[11];             /* Cursors in the equivalence class */
+  i16 aiColumn[11];          /* Corresponding column number in the eq-class */
 };
 
 /*
@@ -117298,7 +118416,7 @@ struct WhereInfo {
   u16 wctrlFlags;           /* Flags originally passed to sqlite3WhereBegin() */
   i8 nOBSat;                /* Number of ORDER BY terms satisfied by indices */
   u8 sorted;                /* True if really sorted (not just grouped) */
-  u8 okOnePass;             /* Ok to use one-pass algorithm for UPDATE/DELETE */
+  u8 eOnePass;              /* ONEPASS_OFF, or _SINGLE, or _MULTI */
   u8 untestedTerms;         /* Not all WHERE terms resolved by outer loop */
   u8 eDistinct;             /* One of the WHERE_DISTINCT_* values below */
   u8 nLevel;                /* Number of nested loop */
@@ -117363,6 +118481,7 @@ SQLITE_PRIVATE void sqlite3WhereSplit(WhereClause*,Expr*,u8);
 SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet*, Expr*);
 SQLITE_PRIVATE Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*);
 SQLITE_PRIVATE void sqlite3WhereExprAnalyze(SrcList*, WhereClause*);
+SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereClause*);
 
 
 
@@ -117440,6 +118559,16 @@ static void explainAppendTerm(
   sqlite3StrAccumAppend(pStr, "?", 1);
 }
 
+/*
+** Return the name of the i-th column of the pIdx index.
+*/
+static const char *explainIndexColumnName(Index *pIdx, int i){
+  i = pIdx->aiColumn[i];
+  if( i==XN_EXPR ) return "<expr>";
+  if( i==XN_ROWID ) return "rowid";
+  return pIdx->pTable->aCol[i].zName;
+}
+
 /*
 ** Argument pLevel describes a strategy for scanning table pTab. This 
 ** function appends text to pStr that describes the subset of table
@@ -117454,33 +118583,27 @@ static void explainAppendTerm(
 **
 **   "a=? AND b>?"
 */
-static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){
+static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){
   Index *pIndex = pLoop->u.btree.pIndex;
   u16 nEq = pLoop->u.btree.nEq;
   u16 nSkip = pLoop->nSkip;
   int i, j;
-  Column *aCol = pTab->aCol;
-  i16 *aiColumn = pIndex->aiColumn;
 
   if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return;
   sqlite3StrAccumAppend(pStr, " (", 2);
   for(i=0; i<nEq; i++){
-    char *z = aiColumn[i] < 0 ? "rowid" : aCol[aiColumn[i]].zName;
-    if( i>=nSkip ){
-      explainAppendTerm(pStr, i, z, "=");
-    }else{
-      if( i ) sqlite3StrAccumAppend(pStr, " AND ", 5);
-      sqlite3XPrintf(pStr, 0, "ANY(%s)", z);
-    }
+    const char *z = explainIndexColumnName(pIndex, i);
+    if( i ) sqlite3StrAccumAppend(pStr, " AND ", 5);
+    sqlite3XPrintf(pStr, 0, i>=nSkip ? "%s=?" : "ANY(%s)", z);
   }
 
   j = i;
   if( pLoop->wsFlags&WHERE_BTM_LIMIT ){
-    char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName;
+    const char *z = explainIndexColumnName(pIndex, i);
     explainAppendTerm(pStr, i++, z, ">");
   }
   if( pLoop->wsFlags&WHERE_TOP_LIMIT ){
-    char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName;
+    const char *z = explainIndexColumnName(pIndex, j);
     explainAppendTerm(pStr, i, z, "<");
   }
   sqlite3StrAccumAppend(pStr, ")", 1);
@@ -117561,22 +118684,21 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
       if( zFmt ){
         sqlite3StrAccumAppend(&str, " USING ", 7);
         sqlite3XPrintf(&str, 0, zFmt, pIdx->zName);
-        explainIndexRange(&str, pLoop, pItem->pTab);
+        explainIndexRange(&str, pLoop);
       }
     }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){
-      const char *zRange;
+      const char *zRangeOp;
       if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){
-        zRange = "(rowid=?)";
+        zRangeOp = "=";
       }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){
-        zRange = "(rowid>? AND rowid<?)";
+        zRangeOp = ">? AND rowid<";
       }else if( flags&WHERE_BTM_LIMIT ){
-        zRange = "(rowid>?)";
+        zRangeOp = ">";
       }else{
         assert( flags&WHERE_TOP_LIMIT);
-        zRange = "(rowid<?)";
+        zRangeOp = "<";
       }
-      sqlite3StrAccumAppendAll(&str, " USING INTEGER PRIMARY KEY ");
-      sqlite3StrAccumAppendAll(&str, zRange);
+      sqlite3XPrintf(&str, 0, " USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp);
     }
 #ifndef SQLITE_OMIT_VIRTUALTABLE
     else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
@@ -117891,7 +119013,7 @@ static int codeAllEqualityTerms(
   nReg = pLoop->u.btree.nEq + nExtraReg;
   pParse->nMem += nReg;
 
-  zAff = sqlite3DbStrDup(pParse->db, sqlite3IndexAffinityStr(v, pIdx));
+  zAff = sqlite3DbStrDup(pParse->db,sqlite3IndexAffinityStr(pParse->db,pIdx));
   if( !zAff ){
     pParse->db->mallocFailed = 1;
   }
@@ -117910,8 +119032,8 @@ static int codeAllEqualityTerms(
     sqlite3VdbeJumpHere(v, j);
     for(j=0; j<nSkip; j++){
       sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, j, regBase+j);
-      assert( pIdx->aiColumn[j]>=0 );
-      VdbeComment((v, "%s", pIdx->pTable->aCol[pIdx->aiColumn[j]].zName));
+      testcase( pIdx->aiColumn[j]==XN_EXPR );
+      VdbeComment((v, "%s", explainIndexColumnName(pIdx, j)));
     }
   }    
 
@@ -118045,14 +119167,14 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
   ** initialize a memory cell that records if this table matches any
   ** row of the left table of the join.
   */
-  if( pLevel->iFrom>0 && (pTabItem[0].jointype & JT_LEFT)!=0 ){
+  if( pLevel->iFrom>0 && (pTabItem[0].fg.jointype & JT_LEFT)!=0 ){
     pLevel->iLeftJoin = ++pParse->nMem;
     sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLeftJoin);
     VdbeComment((v, "init LEFT JOIN no-match flag"));
   }
 
   /* Special case of a FROM clause subquery implemented as a co-routine */
-  if( pTabItem->viaCoroutine ){
+  if( pTabItem->fg.viaCoroutine ){
     int regYield = pTabItem->regReturn;
     sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
     pLevel->p2 =  sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk);
@@ -118096,8 +119218,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
         disableTerm(pLevel, pLoop->aLTerm[j]);
       }
     }
-    pLevel->op = OP_VNext;
     pLevel->p1 = iCur;
+    pLevel->op = pWInfo->eOnePass ? OP_Noop : OP_VNext;
     pLevel->p2 = sqlite3VdbeCurrentAddr(v);
     sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
     sqlite3ExprCachePop(pParse);
@@ -118465,7 +119587,12 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
       iRowidReg = ++pParse->nMem;
       sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
       sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
-      sqlite3VdbeAddOp2(v, OP_Seek, iCur, iRowidReg);  /* Deferred seek */
+      if( pWInfo->eOnePass!=ONEPASS_OFF ){
+        sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowidReg);
+        VdbeCoverage(v);
+      }else{
+        sqlite3VdbeAddOp2(v, OP_Seek, iCur, iRowidReg);  /* Deferred seek */
+      }
     }else if( iCur!=iIdxCur ){
       Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
       iRowidReg = sqlite3GetTempRange(pParse, pPk->nKeyCol);
@@ -118657,7 +119784,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
       if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
         WhereInfo *pSubWInfo;           /* Info for single OR-term scan */
         Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */
-        int j1 = 0;                     /* Address of jump operation */
+        int jmp1 = 0;                   /* Address of jump operation */
         if( pAndExpr && !ExprHasProperty(pOrExpr, EP_FromJoin) ){
           pAndExpr->pLeft = pOrExpr;
           pOrExpr = pAndExpr;
@@ -118684,7 +119811,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
             int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
             if( HasRowid(pTab) ){
               r = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, regRowid, 0);
-              j1 = sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, 0, r,iSet);
+              jmp1 = sqlite3VdbeAddOp4Int(v, OP_RowSetTest, regRowset, 0,
+                                           r,iSet);
               VdbeCoverage(v);
             }else{
               Index *pPk = sqlite3PrimaryKeyIndex(pTab);
@@ -118714,7 +119842,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
               ** need to insert the key into the temp table, as it will never 
               ** be tested for.  */ 
               if( iSet ){
-                j1 = sqlite3VdbeAddOp4Int(v, OP_Found, regRowset, 0, r, nPk);
+                jmp1 = sqlite3VdbeAddOp4Int(v, OP_Found, regRowset, 0, r, nPk);
                 VdbeCoverage(v);
               }
               if( iSet>=0 ){
@@ -118733,7 +119861,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
 
           /* Jump here (skipping the main loop body subroutine) if the
           ** current sub-WHERE row is a duplicate from prior sub-WHEREs. */
-          if( j1 ) sqlite3VdbeJumpHere(v, j1);
+          if( jmp1 ) sqlite3VdbeJumpHere(v, jmp1);
 
           /* The pSubWInfo->untestedTerms flag means that this OR term
           ** contained one or more AND term from a notReady table.  The
@@ -118779,7 +119907,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
       sqlite3ExprDelete(db, pAndExpr);
     }
     sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v));
-    sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrBrk);
+    sqlite3VdbeGoto(v, pLevel->addrBrk);
     sqlite3VdbeResolveLabel(v, iLoopBody);
 
     if( pWInfo->nLevel>1 ) sqlite3StackFree(db, pOrTab);
@@ -118794,7 +119922,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
     static const u8 aStep[] = { OP_Next, OP_Prev };
     static const u8 aStart[] = { OP_Rewind, OP_Last };
     assert( bRev==0 || bRev==1 );
-    if( pTabItem->isRecursive ){
+    if( pTabItem->fg.isRecursive ){
       /* Tables marked isRecursive have only a single row that is stored in
       ** a pseudo-cursor.  No need to Rewind or Next such cursors. */
       pLevel->op = OP_Noop;
@@ -119702,6 +120830,51 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
   return mask;
 }
 
+/*
+** Expression pExpr is one operand of a comparison operator that might
+** be useful for indexing.  This routine checks to see if pExpr appears
+** in any index.  Return TRUE (1) if pExpr is an indexed term and return
+** FALSE (0) if not.  If TRUE is returned, also set *piCur to the cursor
+** number of the table that is indexed and *piColumn to the column number
+** of the column that is indexed, or -2 if an expression is being indexed.
+**
+** If pExpr is a TK_COLUMN column reference, then this routine always returns
+** true even if that particular column is not indexed, because the column
+** might be added to an automatic index later.
+*/
+static int exprMightBeIndexed(
+  SrcList *pFrom,        /* The FROM clause */
+  Bitmask mPrereq,       /* Bitmask of FROM clause terms referenced by pExpr */
+  Expr *pExpr,           /* An operand of a comparison operator */
+  int *piCur,            /* Write the referenced table cursor number here */
+  int *piColumn          /* Write the referenced table column number here */
+){
+  Index *pIdx;
+  int i;
+  int iCur;
+  if( pExpr->op==TK_COLUMN ){
+    *piCur = pExpr->iTable;
+    *piColumn = pExpr->iColumn;
+    return 1;
+  }
+  if( mPrereq==0 ) return 0;                 /* No table references */
+  if( (mPrereq&(mPrereq-1))!=0 ) return 0;   /* Refs more than one table */
+  for(i=0; mPrereq>1; i++, mPrereq>>=1){}
+  iCur = pFrom->a[i].iCursor;
+  for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+    if( pIdx->aColExpr==0 ) continue;
+    for(i=0; i<pIdx->nKeyCol; i++){
+      if( pIdx->aiColumn[i]!=(-2) ) continue;
+      if( sqlite3ExprCompare(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){
+        *piCur = iCur;
+        *piColumn = -2;
+        return 1;
+      }
+    }
+  }
+  return 0;
+}
+
 /*
 ** The input to this routine is an WhereTerm structure with only the
 ** "pExpr" field filled in.  The job of this routine is to analyze the
@@ -119772,16 +120945,19 @@ static void exprAnalyze(
   pTerm->iParent = -1;
   pTerm->eOperator = 0;
   if( allowedOp(op) ){
+    int iCur, iColumn;
     Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
     Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
     u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV;
-    if( pLeft->op==TK_COLUMN ){
-      pTerm->leftCursor = pLeft->iTable;
-      pTerm->u.leftColumn = pLeft->iColumn;
+    if( exprMightBeIndexed(pSrc, prereqLeft, pLeft, &iCur, &iColumn) ){
+      pTerm->leftCursor = iCur;
+      pTerm->u.leftColumn = iColumn;
       pTerm->eOperator = operatorMask(op) & opMask;
     }
     if( op==TK_IS ) pTerm->wtFlags |= TERM_IS;
-    if( pRight && pRight->op==TK_COLUMN ){
+    if( pRight 
+     && exprMightBeIndexed(pSrc, pTerm->prereqRight, pRight, &iCur, &iColumn)
+    ){
       WhereTerm *pNew;
       Expr *pDup;
       u16 eExtraOp = 0;        /* Extra bits for pNew->eOperator */
@@ -119809,9 +120985,8 @@ static void exprAnalyze(
         pNew = pTerm;
       }
       exprCommute(pParse, pDup);
-      pLeft = sqlite3ExprSkipCollate(pDup->pLeft);
-      pNew->leftCursor = pLeft->iTable;
-      pNew->u.leftColumn = pLeft->iColumn;
+      pNew->leftCursor = iCur;
+      pNew->u.leftColumn = iColumn;
       testcase( (prereqLeft | extraRight) != prereqLeft );
       pNew->prereqRight = prereqLeft | extraRight;
       pNew->prereqAll = prereqAll;
@@ -120155,6 +121330,46 @@ SQLITE_PRIVATE void sqlite3WhereExprAnalyze(
   }
 }
 
+/*
+** For table-valued-functions, transform the function arguments into
+** new WHERE clause terms.  
+**
+** Each function argument translates into an equality constraint against
+** a HIDDEN column in the table.
+*/
+SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(
+  Parse *pParse,                    /* Parsing context */
+  struct SrcList_item *pItem,       /* The FROM clause term to process */
+  WhereClause *pWC                  /* Xfer function arguments to here */
+){
+  Table *pTab;
+  int j, k;
+  ExprList *pArgs;
+  Expr *pColRef;
+  Expr *pTerm;
+  if( pItem->fg.isTabFunc==0 ) return;
+  pTab = pItem->pTab;
+  assert( pTab!=0 );
+  pArgs = pItem->u1.pFuncArg;
+  assert( pArgs!=0 );
+  for(j=k=0; j<pArgs->nExpr; j++){
+    while( k<pTab->nCol && (pTab->aCol[k].colFlags & COLFLAG_HIDDEN)==0 ){ k++; }
+    if( k>=pTab->nCol ){
+      sqlite3ErrorMsg(pParse, "too many arguments on %s() - max %d",
+                      pTab->zName, j);
+      return;
+    }
+    pColRef = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
+    if( pColRef==0 ) return;
+    pColRef->iTable = pItem->iCursor;
+    pColRef->iColumn = k++;
+    pColRef->pTab = pTab;
+    pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef,
+                         sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0);
+    whereClauseInsert(pWC, pTerm, TERM_DYNAMIC);
+  }
+}
+
 /************** End of whereexpr.c *******************************************/
 /************** Begin file where.c *******************************************/
 /*
@@ -120228,9 +121443,11 @@ SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo *pWInfo){
 }
 
 /*
-** Return TRUE if an UPDATE or DELETE statement can operate directly on
-** the rowids returned by a WHERE clause.  Return FALSE if doing an
-** UPDATE or DELETE might change subsequent WHERE clause results.
+** Return ONEPASS_OFF (0) if an UPDATE or DELETE statement is unable to
+** operate directly on the rowis returned by a WHERE clause.  Return
+** ONEPASS_SINGLE (1) if the statement can operation directly because only
+** a single row is to be changed.  Return ONEPASS_MULTI (2) if the one-pass
+** optimization can be used on multiple 
 **
 ** If the ONEPASS optimization is used (if this routine returns true)
 ** then also write the indices of open cursors used by ONEPASS
@@ -120244,7 +121461,14 @@ SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo *pWInfo){
 */
 SQLITE_PRIVATE int sqlite3WhereOkOnePass(WhereInfo *pWInfo, int *aiCur){
   memcpy(aiCur, pWInfo->aiCurOnePass, sizeof(int)*2);
-  return pWInfo->okOnePass;
+#ifdef WHERETRACE_ENABLED
+  if( sqlite3WhereTrace && pWInfo->eOnePass!=ONEPASS_OFF ){
+    sqlite3DebugPrintf("%s cursors: %d %d\n",
+         pWInfo->eOnePass==ONEPASS_SINGLE ? "ONEPASS_SINGLE" : "ONEPASS_MULTI",
+         aiCur[0], aiCur[1]);
+  }
+#endif
+  return pWInfo->eOnePass;
 }
 
 /*
@@ -120330,37 +121554,39 @@ static void createMask(WhereMaskSet *pMaskSet, int iCursor){
 */
 static WhereTerm *whereScanNext(WhereScan *pScan){
   int iCur;            /* The cursor on the LHS of the term */
-  int iColumn;         /* The column on the LHS of the term.  -1 for IPK */
+  i16 iColumn;         /* The column on the LHS of the term.  -1 for IPK */
   Expr *pX;            /* An expression being tested */
   WhereClause *pWC;    /* Shorthand for pScan->pWC */
   WhereTerm *pTerm;    /* The term being tested */
   int k = pScan->k;    /* Where to start scanning */
 
   while( pScan->iEquiv<=pScan->nEquiv ){
-    iCur = pScan->aEquiv[pScan->iEquiv-2];
-    iColumn = pScan->aEquiv[pScan->iEquiv-1];
+    iCur = pScan->aiCur[pScan->iEquiv-1];
+    iColumn = pScan->aiColumn[pScan->iEquiv-1];
+    if( iColumn==XN_EXPR && pScan->pIdxExpr==0 ) return 0;
     while( (pWC = pScan->pWC)!=0 ){
       for(pTerm=pWC->a+k; k<pWC->nTerm; k++, pTerm++){
         if( pTerm->leftCursor==iCur
          && pTerm->u.leftColumn==iColumn
-         && (pScan->iEquiv<=2 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin))
+         && (iColumn!=XN_EXPR
+             || sqlite3ExprCompare(pTerm->pExpr->pLeft,pScan->pIdxExpr,iCur)==0)
+         && (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin))
         ){
           if( (pTerm->eOperator & WO_EQUIV)!=0
-           && pScan->nEquiv<ArraySize(pScan->aEquiv)
+           && pScan->nEquiv<ArraySize(pScan->aiCur)
+           && (pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight))->op==TK_COLUMN
           ){
             int j;
-            pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight);
-            assert( pX->op==TK_COLUMN );
-            for(j=0; j<pScan->nEquiv; j+=2){
-              if( pScan->aEquiv[j]==pX->iTable
-               && pScan->aEquiv[j+1]==pX->iColumn ){
+            for(j=0; j<pScan->nEquiv; j++){
+              if( pScan->aiCur[j]==pX->iTable
+               && pScan->aiColumn[j]==pX->iColumn ){
                   break;
               }
             }
             if( j==pScan->nEquiv ){
-              pScan->aEquiv[j] = pX->iTable;
-              pScan->aEquiv[j+1] = pX->iColumn;
-              pScan->nEquiv += 2;
+              pScan->aiCur[j] = pX->iTable;
+              pScan->aiColumn[j] = pX->iColumn;
+              pScan->nEquiv++;
             }
           }
           if( (pTerm->eOperator & pScan->opMask)!=0 ){
@@ -120382,8 +121608,8 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
             }
             if( (pTerm->eOperator & (WO_EQ|WO_IS))!=0
              && (pX = pTerm->pExpr->pRight)->op==TK_COLUMN
-             && pX->iTable==pScan->aEquiv[0]
-             && pX->iColumn==pScan->aEquiv[1]
+             && pX->iTable==pScan->aiCur[0]
+             && pX->iColumn==pScan->aiColumn[0]
             ){
               testcase( pTerm->eOperator & WO_IS );
               continue;
@@ -120398,7 +121624,7 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
     }
     pScan->pWC = pScan->pOrigWC;
     k = 0;
-    pScan->iEquiv += 2;
+    pScan->iEquiv++;
   }
   return 0;
 }
@@ -120427,16 +121653,19 @@ static WhereTerm *whereScanInit(
   u32 opMask,             /* Operator(s) to scan for */
   Index *pIdx             /* Must be compatible with this index */
 ){
-  int j;
+  int j = 0;
 
   /* memset(pScan, 0, sizeof(*pScan)); */
   pScan->pOrigWC = pWC;
   pScan->pWC = pWC;
+  pScan->pIdxExpr = 0;
+  if( pIdx ){
+    j = iColumn;
+    iColumn = pIdx->aiColumn[j];
+    if( iColumn==XN_EXPR ) pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr;
+  }
   if( pIdx && iColumn>=0 ){
     pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity;
-    for(j=0; pIdx->aiColumn[j]!=iColumn; j++){
-      if( NEVER(j>pIdx->nColumn) ) return 0;
-    }
     pScan->zCollName = pIdx->azColl[j];
   }else{
     pScan->idxaff = 0;
@@ -120444,10 +121673,10 @@ static WhereTerm *whereScanInit(
   }
   pScan->opMask = opMask;
   pScan->k = 0;
-  pScan->aEquiv[0] = iCur;
-  pScan->aEquiv[1] = iColumn;
-  pScan->nEquiv = 2;
-  pScan->iEquiv = 2;
+  pScan->aiCur[0] = iCur;
+  pScan->aiColumn[0] = iColumn;
+  pScan->nEquiv = 1;
+  pScan->iEquiv = 1;
   return whereScanNext(pScan);
 }
 
@@ -120457,15 +121686,16 @@ static WhereTerm *whereScanInit(
 ** the WO_xx operator codes specified by the op parameter.
 ** Return a pointer to the term.  Return 0 if not found.
 **
+** If pIdx!=0 then search for terms matching the iColumn-th column of pIdx
+** rather than the iColumn-th column of table iCur.
+**
 ** The term returned might by Y=<expr> if there is another constraint in
 ** the WHERE clause that specifies that X=Y.  Any such constraints will be
 ** identified by the WO_EQUIV bit in the pTerm->eOperator field.  The
-** aEquiv[] array holds X and all its equivalents, with each SQL variable
-** taking up two slots in aEquiv[].  The first slot is for the cursor number
-** and the second is for the column number.  There are 22 slots in aEquiv[]
-** so that means we can look for X plus up to 10 other equivalent values.
-** Hence a search for X will return <expr> if X=A1 and A1=A2 and A2=A3
-** and ... and A9=A10 and A10=<expr>.
+** aiCur[]/iaColumn[] arrays hold X and all its equivalents. There are 11
+** slots in aiCur[]/aiColumn[] so that means we can look for X plus up to 10
+** other equivalent values.  Hence a search for X will return <expr> if X=A1
+** and A1=A2 and A2=A3 and ... and A9=A10 and A10=<expr>.
 **
 ** If there are multiple terms in the WHERE clause of the form "X <op> <expr>"
 ** then try for the one with no dependencies on <expr> - in other words where
@@ -120534,6 +121764,25 @@ static int findIndexCol(
   return -1;
 }
 
+/*
+** Return TRUE if the iCol-th column of index pIdx is NOT NULL
+*/
+static int indexColumnNotNull(Index *pIdx, int iCol){
+  int j;
+  assert( pIdx!=0 );
+  assert( iCol>=0 && iCol<pIdx->nColumn );
+  j = pIdx->aiColumn[iCol];
+  if( j>=0 ){
+    return pIdx->pTable->aCol[j].notNull;
+  }else if( j==(-1) ){
+    return 1;
+  }else{
+    assert( j==(-2) );
+    return 0;  /* Assume an indexed expression can always yield a NULL */
+
+  }
+}
+
 /*
 ** Return true if the DISTINCT expression-list passed as the third argument
 ** is redundant.
@@ -120584,12 +121833,9 @@ static int isDistinctRedundant(
   for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
     if( !IsUniqueIndex(pIdx) ) continue;
     for(i=0; i<pIdx->nKeyCol; i++){
-      i16 iCol = pIdx->aiColumn[i];
-      if( 0==sqlite3WhereFindTerm(pWC, iBase, iCol, ~(Bitmask)0, WO_EQ, pIdx) ){
-        int iIdxCol = findIndexCol(pParse, pDistinct, iBase, pIdx, i);
-        if( iIdxCol<0 || pTab->aCol[iCol].notNull==0 ){
-          break;
-        }
+      if( 0==sqlite3WhereFindTerm(pWC, iBase, i, ~(Bitmask)0, WO_EQ, pIdx) ){
+        if( findIndexCol(pParse, pDistinct, iBase, pIdx, i)<0 ) break;
+        if( indexColumnNotNull(pIdx, i)==0 ) break;
       }
     }
     if( i==pIdx->nKeyCol ){
@@ -120855,7 +122101,7 @@ static void constructAutomaticIndex(
     }
   }
   assert( n==nKeyCol );
-  pIdx->aiColumn[n] = -1;
+  pIdx->aiColumn[n] = XN_ROWID;
   pIdx->azColl[n] = "BINARY";
 
   /* Create the automatic index */
@@ -120868,7 +122114,7 @@ static void constructAutomaticIndex(
   /* Fill the automatic index with content */
   sqlite3ExprCachePush(pParse);
   pTabItem = &pWC->pWInfo->pTabList->a[pLevel->iFrom];
-  if( pTabItem->viaCoroutine ){
+  if( pTabItem->fg.viaCoroutine ){
     int regYield = pTabItem->regReturn;
     sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
     addrTop =  sqlite3VdbeAddOp1(v, OP_Yield, regYield);
@@ -120887,10 +122133,10 @@ static void constructAutomaticIndex(
   sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
   sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
   if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
-  if( pTabItem->viaCoroutine ){
+  if( pTabItem->fg.viaCoroutine ){
     translateColumnToCopy(v, addrTop, pLevel->iTabCur, pTabItem->regResult);
-    sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop);
-    pTabItem->viaCoroutine = 0;
+    sqlite3VdbeGoto(v, addrTop);
+    pTabItem->fg.viaCoroutine = 0;
   }else{
     sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v);
   }
@@ -120941,6 +122187,7 @@ static sqlite3_index_info *allocateIndexInfo(
     testcase( pTerm->eOperator & WO_ALL );
     if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue;
     if( pTerm->wtFlags & TERM_VNULL ) continue;
+    assert( pTerm->u.leftColumn>=(-1) );
     nTerm++;
   }
 
@@ -120996,6 +122243,7 @@ static sqlite3_index_info *allocateIndexInfo(
     testcase( pTerm->eOperator & WO_ALL );
     if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue;
     if( pTerm->wtFlags & TERM_VNULL ) continue;
+    assert( pTerm->u.leftColumn>=(-1) );
     pIdxCons[j].iColumn = pTerm->u.leftColumn;
     pIdxCons[j].iTermOffset = i;
     op = (u8)pTerm->eOperator & WO_ALL;
@@ -121286,6 +122534,21 @@ static LogEst whereRangeAdjust(WhereTerm *pTerm, LogEst nNew){
   return nRet;
 }
 
+
+#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+/*
+** Return the affinity for a single column of an index.
+*/
+static char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCol){
+  assert( iCol>=0 && iCol<pIdx->nColumn );
+  if( !pIdx->zColAff ){
+    if( sqlite3IndexAffinityStr(db, pIdx)==0 ) return SQLITE_AFF_BLOB;
+  }
+  return pIdx->zColAff[iCol];
+}
+#endif
+
+
 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
 /* 
 ** This function is called to estimate the number of rows visited by a
@@ -121335,8 +122598,7 @@ static int whereRangeSkipScanEst(
   int nLower = -1;
   int nUpper = p->nSample+1;
   int rc = SQLITE_OK;
-  int iCol = p->aiColumn[nEq];
-  u8 aff = iCol>=0 ? p->pTable->aCol[iCol].affinity : SQLITE_AFF_INTEGER;
+  u8 aff = sqlite3IndexColumnAffinity(db, p, nEq);
   CollSeq *pColl;
   
   sqlite3_value *p1 = 0;          /* Value extracted from pLower */
@@ -121484,11 +122746,8 @@ static int whereRangeScanEst(
         testcase( pRec->nField!=pBuilder->nRecValid );
         pRec->nField = pBuilder->nRecValid;
       }
-      if( nEq==p->nKeyCol ){
-        aff = SQLITE_AFF_INTEGER;
-      }else{
-        aff = p->pTable->aCol[p->aiColumn[nEq]].affinity;
-      }
+      aff = sqlite3IndexColumnAffinity(pParse->db, p, nEq);
+      assert( nEq!=p->nKeyCol || aff==SQLITE_AFF_INTEGER );
       /* Determine iLower and iUpper using ($P) only. */
       if( nEq==0 ){
         iLower = 0;
@@ -121646,7 +122905,7 @@ static int whereEqualScanEst(
     return SQLITE_OK;
   }
 
-  aff = p->pTable->aCol[p->aiColumn[nEq-1]].affinity;
+  aff = sqlite3IndexColumnAffinity(pParse->db, p, nEq-1);
   rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq-1, &bOk);
   pBuilder->pRec = pRec;
   if( rc!=SQLITE_OK ) return rc;
@@ -122073,18 +123332,20 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
   ** and prereqs.
   */
   if( pBuilder->pOrSet!=0 ){
+    if( pTemplate->nLTerm ){
 #if WHERETRACE_ENABLED
-    u16 n = pBuilder->pOrSet->n;
-    int x =
+      u16 n = pBuilder->pOrSet->n;
+      int x =
 #endif
-    whereOrInsert(pBuilder->pOrSet, pTemplate->prereq, pTemplate->rRun,
+      whereOrInsert(pBuilder->pOrSet, pTemplate->prereq, pTemplate->rRun,
                                     pTemplate->nOut);
 #if WHERETRACE_ENABLED /* 0x8 */
-    if( sqlite3WhereTrace & 0x8 ){
-      sqlite3DebugPrintf(x?"   or-%d:  ":"   or-X:  ", n);
-      whereLoopPrint(pTemplate, pBuilder->pWC);
-    }
+      if( sqlite3WhereTrace & 0x8 ){
+        sqlite3DebugPrintf(x?"   or-%d:  ":"   or-X:  ", n);
+        whereLoopPrint(pTemplate, pBuilder->pWC);
+      }
 #endif
+    }
     return SQLITE_OK;
   }
 
@@ -122274,7 +123535,6 @@ static int whereLoopAddBtreeIndex(
   u16 saved_nSkip;                /* Original value of pNew->nSkip */
   u32 saved_wsFlags;              /* Original value of pNew->wsFlags */
   LogEst saved_nOut;              /* Original value of pNew->nOut */
-  int iCol;                       /* Index of the column in the table */
   int rc = SQLITE_OK;             /* Return code */
   LogEst rSize;                   /* Number of rows in the table */
   LogEst rLogSize;                /* Logarithm of table size */
@@ -122287,7 +123547,7 @@ static int whereLoopAddBtreeIndex(
   assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 );
   if( pNew->wsFlags & WHERE_BTM_LIMIT ){
     opMask = WO_LT|WO_LE;
-  }else if( /*pProbe->tnum<=0 ||*/ (pSrc->jointype & JT_LEFT)!=0 ){
+  }else if( /*pProbe->tnum<=0 ||*/ (pSrc->fg.jointype & JT_LEFT)!=0 ){
     opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE;
   }else{
     opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS;
@@ -122295,16 +123555,15 @@ static int whereLoopAddBtreeIndex(
   if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
 
   assert( pNew->u.btree.nEq<pProbe->nColumn );
-  iCol = pProbe->aiColumn[pNew->u.btree.nEq];
 
-  pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol,
-                        opMask, pProbe);
   saved_nEq = pNew->u.btree.nEq;
   saved_nSkip = pNew->nSkip;
   saved_nLTerm = pNew->nLTerm;
   saved_wsFlags = pNew->wsFlags;
   saved_prereq = pNew->prereq;
   saved_nOut = pNew->nOut;
+  pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, saved_nEq,
+                        opMask, pProbe);
   pNew->rSetup = 0;
   rSize = pProbe->aiRowLogEst[0];
   rLogSize = estLog(rSize);
@@ -122317,7 +123576,7 @@ static int whereLoopAddBtreeIndex(
     int nRecValid = pBuilder->nRecValid;
 #endif
     if( (eOp==WO_ISNULL || (pTerm->wtFlags&TERM_VNULL)!=0)
-     && (iCol<0 || pSrc->pTab->aCol[iCol].notNull)
+     && indexColumnNotNull(pProbe, saved_nEq)
     ){
       continue; /* ignore IS [NOT] NULL constraints on NOT NULL columns */
     }
@@ -122354,8 +123613,12 @@ static int whereLoopAddBtreeIndex(
                         ** changes "x IN (?)" into "x=?". */
 
     }else if( eOp & (WO_EQ|WO_IS) ){
+      int iCol = pProbe->aiColumn[saved_nEq];
       pNew->wsFlags |= WHERE_COLUMN_EQ;
-      if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1) ){
+      assert( saved_nEq==pNew->u.btree.nEq );
+      if( iCol==XN_ROWID 
+       || (iCol>0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1)
+      ){
         if( iCol>=0 && pProbe->uniqNotNull==0 ){
           pNew->wsFlags |= WHERE_UNQ_WANTED;
         }else{
@@ -122406,7 +123669,7 @@ static int whereLoopAddBtreeIndex(
       assert( eOp & (WO_ISNULL|WO_EQ|WO_IN|WO_IS) );
 
       assert( pNew->nOut==saved_nOut );
-      if( pTerm->truthProb<=0 && iCol>=0 ){
+      if( pTerm->truthProb<=0 && pProbe->aiColumn[saved_nEq]>=0 ){
         assert( (eOp & WO_IN) || nIn==0 );
         testcase( eOp & WO_IN );
         pNew->nOut += pTerm->truthProb;
@@ -122541,18 +123804,25 @@ static int indexMightHelpWithOrderBy(
   int iCursor
 ){
   ExprList *pOB;
+  ExprList *aColExpr;
   int ii, jj;
 
   if( pIndex->bUnordered ) return 0;
   if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0;
   for(ii=0; ii<pOB->nExpr; ii++){
     Expr *pExpr = sqlite3ExprSkipCollate(pOB->a[ii].pExpr);
-    if( pExpr->op!=TK_COLUMN ) return 0;
-    if( pExpr->iTable==iCursor ){
+    if( pExpr->op==TK_COLUMN && pExpr->iTable==iCursor ){
       if( pExpr->iColumn<0 ) return 1;
       for(jj=0; jj<pIndex->nKeyCol; jj++){
         if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1;
       }
+    }else if( (aColExpr = pIndex->aColExpr)!=0 ){
+      for(jj=0; jj<pIndex->nKeyCol; jj++){
+        if( pIndex->aiColumn[jj]!=XN_EXPR ) continue;
+        if( sqlite3ExprCompare(pExpr,aColExpr->a[jj].pExpr,iCursor)==0 ){
+          return 1;
+        }
+      }
     }
   }
   return 0;
@@ -122582,6 +123852,10 @@ static Bitmask columnsInIndex(Index *pIdx){
 static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){
   int i;
   WhereTerm *pTerm;
+  while( pWhere->op==TK_AND ){
+    if( !whereUsablePartialIndex(iTab,pWC,pWhere->pLeft) ) return 0;
+    pWhere = pWhere->pRight;
+  }
   for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
     Expr *pExpr = pTerm->pExpr;
     if( sqlite3ExprImpliesExpr(pExpr, pWhere, iTab) 
@@ -122657,9 +123931,9 @@ static int whereLoopAddBtree(
   pWC = pBuilder->pWC;
   assert( !IsVirtual(pSrc->pTab) );
 
-  if( pSrc->pIndex ){
+  if( pSrc->pIBIndex ){
     /* An INDEXED BY clause specifies a particular index to use */
-    pProbe = pSrc->pIndex;
+    pProbe = pSrc->pIBIndex;
   }else if( !HasRowid(pTab) ){
     pProbe = pTab->pIndex;
   }else{
@@ -122679,7 +123953,7 @@ static int whereLoopAddBtree(
     aiRowEstPk[0] = pTab->nRowLogEst;
     aiRowEstPk[1] = 0;
     pFirst = pSrc->pTab->pIndex;
-    if( pSrc->notIndexed==0 ){
+    if( pSrc->fg.notIndexed==0 ){
       /* The real indices of the table are only considered if the
       ** NOT INDEXED qualifier is omitted from the FROM clause */
       sPk.pNext = pFirst;
@@ -122691,14 +123965,14 @@ static int whereLoopAddBtree(
 
 #ifndef SQLITE_OMIT_AUTOMATIC_INDEX
   /* Automatic indexes */
-  if( !pBuilder->pOrSet   /* Not part of an OR optimization */
+  if( !pBuilder->pOrSet      /* Not part of an OR optimization */
    && (pWInfo->wctrlFlags & WHERE_NO_AUTOINDEX)==0
    && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0
-   && pSrc->pIndex==0     /* Has no INDEXED BY clause */
-   && !pSrc->notIndexed   /* Has no NOT INDEXED clause */
-   && HasRowid(pTab)      /* Is not a WITHOUT ROWID table. (FIXME: Why not?) */
-   && !pSrc->isCorrelated /* Not a correlated subquery */
-   && !pSrc->isRecursive  /* Not a recursive common table expression. */
+   && pSrc->pIBIndex==0      /* Has no INDEXED BY clause */
+   && !pSrc->fg.notIndexed   /* Has no NOT INDEXED clause */
+   && HasRowid(pTab)         /* Not WITHOUT ROWID table. (FIXME: Why not?) */
+   && !pSrc->fg.isCorrelated /* Not a correlated subquery */
+   && !pSrc->fg.isRecursive  /* Not a recursive common table expression. */
   ){
     /* Generate auto-index WhereLoops */
     WhereTerm *pTerm;
@@ -122819,7 +124093,7 @@ static int whereLoopAddBtree(
 
     /* If there was an INDEXED BY clause, then only that one index is
     ** considered. */
-    if( pSrc->pIndex ) break;
+    if( pSrc->pIBIndex ) break;
   }
   return rc;
 }
@@ -122941,6 +124215,7 @@ static int whereLoopAddVirtual(
     pIdxInfo->orderByConsumed = 0;
     pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2;
     pIdxInfo->estimatedRows = 25;
+    pIdxInfo->idxFlags = 0;
     rc = vtabBestIndex(pParse, pTab, pIdxInfo);
     if( rc ) goto whereLoopAddVtab_exit;
     pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
@@ -122986,6 +124261,7 @@ static int whereLoopAddVirtual(
           ** (2) Multiple outputs from a single IN value will not merge
           ** together.  */
           pIdxInfo->orderByConsumed = 0;
+          pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE;
         }
       }
     }
@@ -123001,6 +124277,14 @@ static int whereLoopAddVirtual(
       pNew->rSetup = 0;
       pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
       pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows);
+
+      /* Set the WHERE_ONEROW flag if the xBestIndex() method indicated
+      ** that the scan will visit at most one row. Clear it otherwise. */
+      if( pIdxInfo->idxFlags & SQLITE_INDEX_SCAN_UNIQUE ){
+        pNew->wsFlags |= WHERE_ONEROW;
+      }else{
+        pNew->wsFlags &= ~WHERE_ONEROW;
+      }
       whereLoopInsert(pBuilder, pNew);
       if( pNew->u.vtab.needFree ){
         sqlite3_free(pNew->u.vtab.idxStr);
@@ -123165,16 +124449,16 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
     Bitmask mUnusable = 0;
     pNew->iTab = iTab;
     pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor);
-    if( ((pItem->jointype|priorJointype) & (JT_LEFT|JT_CROSS))!=0 ){
+    if( ((pItem->fg.jointype|priorJointype) & (JT_LEFT|JT_CROSS))!=0 ){
       /* This condition is true when pItem is the FROM clause term on the
       ** right-hand-side of a LEFT or CROSS JOIN.  */
       mExtra = mPrior;
     }
-    priorJointype = pItem->jointype;
+    priorJointype = pItem->fg.jointype;
     if( IsVirtual(pItem->pTab) ){
       struct SrcList_item *p;
       for(p=&pItem[1]; p<pEnd; p++){
-        if( mUnusable || (p->jointype & (JT_LEFT|JT_CROSS)) ){
+        if( mUnusable || (p->fg.jointype & (JT_LEFT|JT_CROSS)) ){
           mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor);
         }
       }
@@ -123322,7 +124606,8 @@ static i8 wherePathSatisfiesOrderBy(
         nKeyCol = pIndex->nKeyCol;
         nColumn = pIndex->nColumn;
         assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) );
-        assert( pIndex->aiColumn[nColumn-1]==(-1) || !HasRowid(pIndex->pTable));
+        assert( pIndex->aiColumn[nColumn-1]==XN_ROWID
+                          || !HasRowid(pIndex->pTable));
         isOrderDistinct = IsUniqueIndex(pIndex);
       }
 
@@ -123354,7 +124639,7 @@ static i8 wherePathSatisfiesOrderBy(
           revIdx = pIndex->aSortOrder[j];
           if( iColumn==pIndex->pTable->iPKey ) iColumn = -1;
         }else{
-          iColumn = -1;
+          iColumn = XN_ROWID;
           revIdx = 0;
         }
 
@@ -123380,9 +124665,15 @@ static i8 wherePathSatisfiesOrderBy(
           testcase( wctrlFlags & WHERE_GROUPBY );
           testcase( wctrlFlags & WHERE_DISTINCTBY );
           if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0;
-          if( pOBExpr->op!=TK_COLUMN ) continue;
-          if( pOBExpr->iTable!=iCur ) continue;
-          if( pOBExpr->iColumn!=iColumn ) continue;
+          if( iColumn>=(-1) ){
+            if( pOBExpr->op!=TK_COLUMN ) continue;
+            if( pOBExpr->iTable!=iCur ) continue;
+            if( pOBExpr->iColumn!=iColumn ) continue;
+          }else{
+            if( sqlite3ExprCompare(pOBExpr,pIndex->aColExpr->a[j].pExpr,iCur) ){
+              continue;
+            }
+          }
           if( iColumn>=0 ){
             pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
             if( !pColl ) pColl = db->pDfltColl;
@@ -123904,7 +125195,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
   pItem = pWInfo->pTabList->a;
   pTab = pItem->pTab;
   if( IsVirtual(pTab) ) return 0;
-  if( pItem->zIndexedBy ) return 0;
+  if( pItem->fg.isIndexedBy ) return 0;
   iCur = pItem->iCursor;
   pWC = &pWInfo->sWC;
   pLoop = pBuilder->pNew;
@@ -123929,7 +125220,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
       ) continue;
       opMask = pIdx->uniqNotNull ? (WO_EQ|WO_IS) : WO_EQ;
       for(j=0; j<pIdx->nKeyCol; j++){
-        pTerm = sqlite3WhereFindTerm(pWC, iCur, pIdx->aiColumn[j], 0, opMask, pIdx);
+        pTerm = sqlite3WhereFindTerm(pWC, iCur, j, 0, opMask, pIdx);
         if( pTerm==0 ) break;
         testcase( pTerm->eOperator & WO_IS );
         pLoop->aLTerm[j] = pTerm;
@@ -124075,6 +125366,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
   sqlite3 *db;               /* Database connection */
   int rc;                    /* Return code */
 
+  assert( (wctrlFlags & WHERE_ONEPASS_MULTIROW)==0 || (
+        (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 
+     && (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 
+  ));
 
   /* Variable initialization */
   db = pParse->db;
@@ -124130,6 +125425,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
   pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(v);
   pWInfo->wctrlFlags = wctrlFlags;
   pWInfo->savedNQueryLoop = pParse->nQueryLoop;
+  assert( pWInfo->eOnePass==ONEPASS_OFF );  /* ONEPASS defaults to OFF */
   pMaskSet = &pWInfo->sMaskSet;
   sWLB.pWInfo = pWInfo;
   sWLB.pWC = &pWInfo->sWC;
@@ -124169,14 +125465,12 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
 
   /* Assign a bit from the bitmask to every term in the FROM clause.
   **
-  ** When assigning bitmask values to FROM clause cursors, it must be
-  ** the case that if X is the bitmask for the N-th FROM clause term then
-  ** the bitmask for all FROM clause terms to the left of the N-th term
-  ** is (X-1).   An expression from the ON clause of a LEFT JOIN can use
-  ** its Expr.iRightJoinTable value to find the bitmask of the right table
-  ** of the join.  Subtracting one from the right table bitmask gives a
-  ** bitmask for all tables to the left of the join.  Knowing the bitmask
-  ** for all tables to the left of a left join is important.  Ticket #3015.
+  ** The N-th term of the FROM clause is assigned a bitmask of 1<<N.
+  **
+  ** The rule of the previous sentence ensures thta if X is the bitmask for
+  ** a table T, then X-1 is the bitmask for all other tables to the left of T.
+  ** Knowing the bitmask for all tables to the left of a left join is
+  ** important.  Ticket #3015.
   **
   ** Note that bitmasks are created for all pTabList->nSrc tables in
   ** pTabList, not just the first nTabList tables.  nTabList is normally
@@ -124185,15 +125479,12 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
   */
   for(ii=0; ii<pTabList->nSrc; ii++){
     createMask(pMaskSet, pTabList->a[ii].iCursor);
+    sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC);
   }
-#ifndef NDEBUG
-  {
-    Bitmask toTheLeft = 0;
-    for(ii=0; ii<pTabList->nSrc; ii++){
-      Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor);
-      assert( (m-1)==toTheLeft );
-      toTheLeft |= m;
-    }
+#ifdef SQLITE_DEBUG
+  for(ii=0; ii<pTabList->nSrc; ii++){
+    Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor);
+    assert( m==MASKBIT(ii) );
   }
 #endif
 
@@ -124213,7 +125504,8 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
   }
 
   /* Construct the WhereLoop objects */
-  WHERETRACE(0xffff,("*** Optimizer Start ***\n"));
+  WHERETRACE(0xffff,("*** Optimizer Start *** (wctrlFlags: 0x%x)\n",
+             wctrlFlags));
 #if defined(WHERETRACE_ENABLED)
   if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */
     int i;
@@ -124291,7 +125583,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
     while( pWInfo->nLevel>=2 ){
       WhereTerm *pTerm, *pEnd;
       pLoop = pWInfo->a[pWInfo->nLevel-1].pWLoop;
-      if( (pWInfo->pTabList->a[pLoop->iTab].jointype & JT_LEFT)==0 ) break;
+      if( (pWInfo->pTabList->a[pLoop->iTab].fg.jointype & JT_LEFT)==0 ) break;
       if( (wctrlFlags & WHERE_WANT_DISTINCT)==0
        && (pLoop->wsFlags & WHERE_ONEROW)==0
       ){
@@ -124321,11 +125613,16 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
   ** the statement to update or delete a single row.
   */
   assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 );
-  if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 
-   && (pWInfo->a[0].pWLoop->wsFlags & WHERE_ONEROW)!=0 ){
-    pWInfo->okOnePass = 1;
-    if( HasRowid(pTabList->a[0].pTab) ){
-      pWInfo->a[0].pWLoop->wsFlags &= ~WHERE_IDX_ONLY;
+  if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){
+    int wsFlags = pWInfo->a[0].pWLoop->wsFlags;
+    int bOnerow = (wsFlags & WHERE_ONEROW)!=0;
+    if( bOnerow || ( (wctrlFlags & WHERE_ONEPASS_MULTIROW)
+       && 0==(wsFlags & WHERE_VIRTUALTABLE)
+    )){
+      pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI;
+      if( HasRowid(pTabList->a[0].pTab) ){
+        pWInfo->a[0].pWLoop->wsFlags &= ~WHERE_IDX_ONLY;
+      }
     }
   }
 
@@ -124356,15 +125653,15 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
     if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
          && (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 ){
       int op = OP_OpenRead;
-      if( pWInfo->okOnePass ){
+      if( pWInfo->eOnePass!=ONEPASS_OFF ){
         op = OP_OpenWrite;
         pWInfo->aiCurOnePass[0] = pTabItem->iCursor;
       };
       sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op);
       assert( pTabItem->iCursor==pLevel->iTabCur );
-      testcase( !pWInfo->okOnePass && pTab->nCol==BMS-1 );
-      testcase( !pWInfo->okOnePass && pTab->nCol==BMS );
-      if( !pWInfo->okOnePass && pTab->nCol<BMS && HasRowid(pTab) ){
+      testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS-1 );
+      testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS );
+      if( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol<BMS && HasRowid(pTab) ){
         Bitmask b = pTabItem->colUsed;
         int n = 0;
         for(; b; b=b>>1, n++){}
@@ -124392,7 +125689,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
         ** WITHOUT ROWID table.  No need for a separate index */
         iIndexCur = pLevel->iTabCur;
         op = 0;
-      }else if( pWInfo->okOnePass ){
+      }else if( pWInfo->eOnePass!=ONEPASS_OFF ){
         Index *pJ = pTabItem->pTab->pIndex;
         iIndexCur = iIdxCur;
         assert( wctrlFlags & WHERE_ONEPASS_DESIRED );
@@ -124529,7 +125826,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
     }
     sqlite3VdbeResolveLabel(v, pLevel->addrBrk);
     if( pLevel->addrSkip ){
-      sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrSkip);
+      sqlite3VdbeGoto(v, pLevel->addrSkip);
       VdbeComment((v, "next skip-scan on %s", pLoop->u.btree.pIndex->zName));
       sqlite3VdbeJumpHere(v, pLevel->addrSkip);
       sqlite3VdbeJumpHere(v, pLevel->addrSkip-2);
@@ -124557,7 +125854,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
       if( pLevel->op==OP_Return ){
         sqlite3VdbeAddOp2(v, OP_Gosub, pLevel->p1, pLevel->addrFirst);
       }else{
-        sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrFirst);
+        sqlite3VdbeGoto(v, pLevel->addrFirst);
       }
       sqlite3VdbeJumpHere(v, addr);
     }
@@ -124584,7 +125881,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
     ** the co-routine into OP_Copy of result contained in a register.
     ** OP_Rowid becomes OP_Null.
     */
-    if( pTabItem->viaCoroutine && !db->mallocFailed ){
+    if( pTabItem->fg.viaCoroutine && !db->mallocFailed ){
       translateColumnToCopy(v, pLevel->addrBody, pLevel->iTabCur,
                             pTabItem->regResult);
       continue;
@@ -124600,7 +125897,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
      && (pWInfo->wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0
     ){
       int ws = pLoop->wsFlags;
-      if( !pWInfo->okOnePass && (ws & WHERE_IDX_ONLY)==0 ){
+      if( pWInfo->eOnePass==ONEPASS_OFF && (ws & WHERE_IDX_ONLY)==0 ){
         sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor);
       }
       if( (ws & WHERE_INDEXED)!=0
@@ -124627,7 +125924,10 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
     }else if( pLoop->wsFlags & WHERE_MULTI_OR ){
       pIdx = pLevel->u.pCovidx;
     }
-    if( pIdx && !db->mallocFailed ){
+    if( pIdx
+     && (pWInfo->eOnePass==ONEPASS_OFF || !HasRowid(pIdx->pTable))
+     && !db->mallocFailed
+    ){
       last = sqlite3VdbeCurrentAddr(v);
       k = pLevel->addrBody;
       pOp = sqlite3VdbeGetOp(v, k);
@@ -124639,6 +125939,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
           if( !HasRowid(pTab) ){
             Index *pPk = sqlite3PrimaryKeyIndex(pTab);
             x = pPk->aiColumn[x];
+            assert( x>=0 );
           }
           x = sqlite3ColumnOfIndex(pIdx, x);
           if( x>=0 ){
@@ -124818,6 +126119,29 @@ struct AttachKey { int type;  Token key; };
     pOut->zStart = pPreOp->z;
     pOut->zEnd = pOperand->zEnd;
   }
+
+  /* Add a single new term to an ExprList that is used to store a
+  ** list of identifiers.  Report an error if the ID list contains
+  ** a COLLATE clause or an ASC or DESC keyword, except ignore the
+  ** error while parsing a legacy schema.
+  */
+  static ExprList *parserAddExprIdListTerm(
+    Parse *pParse,
+    ExprList *pPrior,
+    Token *pIdToken,
+    int hasCollate,
+    int sortOrder
+  ){
+    ExprList *p = sqlite3ExprListAppend(pParse, pPrior, 0);
+    if( (hasCollate || sortOrder!=SQLITE_SO_UNDEFINED)
+        && pParse->db->init.busy==0
+    ){
+      sqlite3ErrorMsg(pParse, "syntax error after column name \"%.*s\"",
+                         pIdToken->n, pIdToken->z);
+    }
+    sqlite3ExprListSetName(pParse, p, pIdToken, 1);
+    return p;
+  }
 /* Next is all token values, in a form suitable for use by makeheaders.
 ** This section will be null unless lemon is run with the -m switch.
 */
@@ -124862,10 +126186,17 @@ struct AttachKey { int type;  Token key; };
 **    sqlite3ParserARG_PDECL     A parameter declaration for the %extra_argument
 **    sqlite3ParserARG_STORE     Code to store %extra_argument into yypParser
 **    sqlite3ParserARG_FETCH     Code to extract %extra_argument from yypParser
-**    YYNSTATE           the combined number of states.
-**    YYNRULE            the number of rules in the grammar
 **    YYERRORSYMBOL      is the code number of the error symbol.  If not
 **                       defined, then do no error processing.
+**    YYNSTATE           the combined number of states.
+**    YYNRULE            the number of rules in the grammar
+**    YY_MAX_SHIFT       Maximum value for shift actions
+**    YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions
+**    YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions
+**    YY_MIN_REDUCE      Maximum value for reduce actions
+**    YY_ERROR_ACTION    The yy_action[] code for syntax error
+**    YY_ACCEPT_ACTION   The yy_action[] code for accept
+**    YY_NO_ACTION       The yy_action[] code for no-op
 */
 #define YYCODETYPE unsigned char
 #define YYNOCODE 254
@@ -124898,12 +126229,17 @@ typedef union {
 #define sqlite3ParserARG_PDECL ,Parse *pParse
 #define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse
 #define sqlite3ParserARG_STORE yypParser->pParse = pParse
-#define YYNSTATE 642
-#define YYNRULE 327
 #define YYFALLBACK 1
-#define YY_NO_ACTION      (YYNSTATE+YYNRULE+2)
-#define YY_ACCEPT_ACTION  (YYNSTATE+YYNRULE+1)
-#define YY_ERROR_ACTION   (YYNSTATE+YYNRULE)
+#define YYNSTATE             436
+#define YYNRULE              328
+#define YY_MAX_SHIFT         435
+#define YY_MIN_SHIFTREDUCE   649
+#define YY_MAX_SHIFTREDUCE   976
+#define YY_MIN_REDUCE        977
+#define YY_MAX_REDUCE        1304
+#define YY_ERROR_ACTION      1305
+#define YY_ACCEPT_ACTION     1306
+#define YY_NO_ACTION         1307
 
 /* The yyzerominor constant is used to initialize instances of
 ** YYMINORTYPE objects to zero. */
@@ -124930,16 +126266,20 @@ static const YYMINORTYPE yyzerominor = { 0 };
 ** Suppose the action integer is N.  Then the action is determined as
 ** follows
 **
-**   0 <= N < YYNSTATE                  Shift N.  That is, push the lookahead
+**   0 <= N <= YY_MAX_SHIFT             Shift N.  That is, push the lookahead
 **                                      token onto the stack and goto state N.
 **
-**   YYNSTATE <= N < YYNSTATE+YYNRULE   Reduce by rule N-YYNSTATE.
+**   N between YY_MIN_SHIFTREDUCE       Shift to an arbitrary state then
+**     and YY_MAX_SHIFTREDUCE           reduce by rule N-YY_MIN_SHIFTREDUCE.
 **
-**   N == YYNSTATE+YYNRULE              A syntax error has occurred.
+**   N between YY_MIN_REDUCE            Reduce by rule N-YY_MIN_REDUCE
+**     and YY_MAX_REDUCE
+
+**   N == YY_ERROR_ACTION               A syntax error has occurred.
 **
-**   N == YYNSTATE+YYNRULE+1            The parser accepts its input.
+**   N == YY_ACCEPT_ACTION              The parser accepts its input.
 **
-**   N == YYNSTATE+YYNRULE+2            No such action.  Denotes unused
+**   N == YY_NO_ACTION                  No such action.  Denotes unused
 **                                      slots in the yy_action[] table.
 **
 ** The action table is constructed as a single large table named yy_action[].
@@ -124969,463 +126309,446 @@ static const YYMINORTYPE yyzerominor = { 0 };
 **                     shifting non-terminals after a reduce.
 **  yy_default[]       Default action for each state.
 */
-#define YY_ACTTAB_COUNT (1497)
+#define YY_ACTTAB_COUNT (1501)
 static const YYACTIONTYPE yy_action[] = {
- /*     0 */   306,  212,  432,  955,  639,  191,  955,  295,  559,   88,
- /*    10 */    88,   88,   88,   81,   86,   86,   86,   86,   85,   85,
- /*    20 */    84,   84,   84,   83,  330,  185,  184,  183,  635,  635,
- /*    30 */   292,  606,  606,   88,   88,   88,   88,  683,   86,   86,
- /*    40 */    86,   86,   85,   85,   84,   84,   84,   83,  330,   16,
- /*    50 */   436,  597,   89,   90,   80,  600,  599,  601,  601,   87,
- /*    60 */    87,   88,   88,   88,   88,  684,   86,   86,   86,   86,
- /*    70 */    85,   85,   84,   84,   84,   83,  330,  306,  559,   84,
- /*    80 */    84,   84,   83,  330,   65,   86,   86,   86,   86,   85,
- /*    90 */    85,   84,   84,   84,   83,  330,  635,  635,  634,  633,
- /*   100 */   182,  682,  550,  379,  376,  375,   17,  322,  606,  606,
- /*   110 */   371,  198,  479,   91,  374,   82,   79,  165,   85,   85,
- /*   120 */    84,   84,   84,   83,  330,  598,  635,  635,  107,   89,
- /*   130 */    90,   80,  600,  599,  601,  601,   87,   87,   88,   88,
- /*   140 */    88,   88,  186,   86,   86,   86,   86,   85,   85,   84,
- /*   150 */    84,   84,   83,  330,  306,  594,  594,  142,  328,  327,
- /*   160 */   484,  249,  344,  238,  635,  635,  634,  633,  585,  448,
- /*   170 */   526,  525,  229,  388,    1,  394,  450,  584,  449,  635,
- /*   180 */   635,  635,  635,  319,  395,  606,  606,  199,  157,  273,
- /*   190 */   382,  268,  381,  187,  635,  635,  634,  633,  311,  555,
- /*   200 */   266,  593,  593,  266,  347,  588,   89,   90,   80,  600,
- /*   210 */   599,  601,  601,   87,   87,   88,   88,   88,   88,  478,
- /*   220 */    86,   86,   86,   86,   85,   85,   84,   84,   84,   83,
- /*   230 */   330,  306,  272,  536,  634,  633,  146,  610,  197,  310,
- /*   240 */   575,  182,  482,  271,  379,  376,  375,  506,   21,  634,
- /*   250 */   633,  634,  633,  635,  635,  374,  611,  574,  548,  440,
- /*   260 */   111,  563,  606,  606,  634,  633,  324,  479,  608,  608,
- /*   270 */   608,  300,  435,  573,  119,  407,  210,  162,  562,  883,
- /*   280 */   592,  592,  306,   89,   90,   80,  600,  599,  601,  601,
- /*   290 */    87,   87,   88,   88,   88,   88,  506,   86,   86,   86,
- /*   300 */    86,   85,   85,   84,   84,   84,   83,  330,  620,  111,
- /*   310 */   635,  635,  361,  606,  606,  358,  249,  349,  248,  433,
- /*   320 */   243,  479,  586,  634,  633,  195,  611,   93,  119,  221,
- /*   330 */   575,  497,  534,  534,   89,   90,   80,  600,  599,  601,
- /*   340 */   601,   87,   87,   88,   88,   88,   88,  574,   86,   86,
- /*   350 */    86,   86,   85,   85,   84,   84,   84,   83,  330,  306,
- /*   360 */    77,  429,  638,  573,  589,  530,  240,  230,  242,  105,
- /*   370 */   249,  349,  248,  515,  588,  208,  460,  529,  564,  173,
- /*   380 */   634,  633,  970,  144,  430,    2,  424,  228,  380,  557,
- /*   390 */   606,  606,  190,  153,  159,  158,  514,   51,  632,  631,
- /*   400 */   630,   71,  536,  432,  954,  196,  610,  954,  614,   45,
- /*   410 */    18,   89,   90,   80,  600,  599,  601,  601,   87,   87,
- /*   420 */    88,   88,   88,   88,  261,   86,   86,   86,   86,   85,
- /*   430 */    85,   84,   84,   84,   83,  330,  306,  608,  608,  608,
- /*   440 */   542,  424,  402,  385,  241,  506,  451,  320,  211,  543,
- /*   450 */   164,  436,  386,  293,  451,  587,  108,  496,  111,  334,
- /*   460 */   391,  591,  424,  614,   27,  452,  453,  606,  606,   72,
- /*   470 */   257,   70,  259,  452,  339,  342,  564,  582,   68,  415,
- /*   480 */   469,  328,  327,   62,  614,   45,  110,  393,   89,   90,
- /*   490 */    80,  600,  599,  601,  601,   87,   87,   88,   88,   88,
- /*   500 */    88,  152,   86,   86,   86,   86,   85,   85,   84,   84,
- /*   510 */    84,   83,  330,  306,  110,  499,  520,  538,  402,  389,
- /*   520 */   424,  110,  566,  500,  593,  593,  454,   82,   79,  165,
- /*   530 */   424,  591,  384,  564,  340,  615,  188,  162,  424,  350,
- /*   540 */   616,  424,  614,   44,  606,  606,  445,  582,  300,  434,
- /*   550 */   151,   19,  614,    9,  568,  580,  348,  615,  469,  567,
- /*   560 */   614,   26,  616,  614,   45,   89,   90,   80,  600,  599,
- /*   570 */   601,  601,   87,   87,   88,   88,   88,   88,  411,   86,
- /*   580 */    86,   86,   86,   85,   85,   84,   84,   84,   83,  330,
- /*   590 */   306,  579,  110,  578,  521,  282,  433,  398,  400,  255,
- /*   600 */   486,   82,   79,  165,  487,  164,   82,   79,  165,  488,
- /*   610 */   488,  364,  387,  424,  544,  544,  509,  350,  362,  155,
- /*   620 */   191,  606,  606,  559,  642,  640,  333,   82,   79,  165,
- /*   630 */   305,  564,  507,  312,  357,  614,   45,  329,  596,  595,
- /*   640 */   194,  337,   89,   90,   80,  600,  599,  601,  601,   87,
- /*   650 */    87,   88,   88,   88,   88,  424,   86,   86,   86,   86,
- /*   660 */    85,   85,   84,   84,   84,   83,  330,  306,   20,  323,
- /*   670 */   150,  263,  211,  543,  421,  596,  595,  614,   22,  424,
- /*   680 */   193,  424,  284,  424,  391,  424,  509,  424,  577,  424,
- /*   690 */   186,  335,  424,  559,  424,  313,  120,  546,  606,  606,
- /*   700 */    67,  614,   47,  614,   50,  614,   48,  614,  100,  614,
- /*   710 */    99,  614,  101,  576,  614,  102,  614,  109,  326,   89,
- /*   720 */    90,   80,  600,  599,  601,  601,   87,   87,   88,   88,
- /*   730 */    88,   88,  424,   86,   86,   86,   86,   85,   85,   84,
- /*   740 */    84,   84,   83,  330,  306,  424,  311,  424,  585,   54,
- /*   750 */   424,  516,  517,  590,  614,  112,  424,  584,  424,  572,
- /*   760 */   424,  195,  424,  571,  424,   67,  424,  614,   94,  614,
- /*   770 */    98,  424,  614,   97,  264,  606,  606,  195,  614,   46,
- /*   780 */   614,   96,  614,   30,  614,   49,  614,  115,  614,  114,
- /*   790 */   418,  229,  388,  614,  113,  306,   89,   90,   80,  600,
- /*   800 */   599,  601,  601,   87,   87,   88,   88,   88,   88,  424,
- /*   810 */    86,   86,   86,   86,   85,   85,   84,   84,   84,   83,
- /*   820 */   330,  119,  424,  590,  110,  372,  606,  606,  195,   53,
- /*   830 */   250,  614,   29,  195,  472,  438,  729,  190,  302,  498,
- /*   840 */    14,  523,  641,    2,  614,   43,  306,   89,   90,   80,
- /*   850 */   600,  599,  601,  601,   87,   87,   88,   88,   88,   88,
- /*   860 */   424,   86,   86,   86,   86,   85,   85,   84,   84,   84,
- /*   870 */    83,  330,  424,  613,  964,  964,  354,  606,  606,  420,
- /*   880 */   312,   64,  614,   42,  391,  355,  283,  437,  301,  255,
- /*   890 */   414,  410,  495,  492,  614,   28,  471,  306,   89,   90,
- /*   900 */    80,  600,  599,  601,  601,   87,   87,   88,   88,   88,
- /*   910 */    88,  424,   86,   86,   86,   86,   85,   85,   84,   84,
- /*   920 */    84,   83,  330,  424,  110,  110,  110,  110,  606,  606,
- /*   930 */   110,  254,   13,  614,   41,  532,  531,  283,  481,  531,
- /*   940 */   457,  284,  119,  561,  356,  614,   40,  284,  306,   89,
- /*   950 */    78,   80,  600,  599,  601,  601,   87,   87,   88,   88,
- /*   960 */    88,   88,  424,   86,   86,   86,   86,   85,   85,   84,
- /*   970 */    84,   84,   83,  330,  110,  424,  341,  220,  555,  606,
- /*   980 */   606,  351,  555,  318,  614,   95,  413,  255,   83,  330,
- /*   990 */   284,  284,  255,  640,  333,  356,  255,  614,   39,  306,
- /*  1000 */   356,   90,   80,  600,  599,  601,  601,   87,   87,   88,
- /*  1010 */    88,   88,   88,  424,   86,   86,   86,   86,   85,   85,
- /*  1020 */    84,   84,   84,   83,  330,  424,  317,  316,  141,  465,
- /*  1030 */   606,  606,  219,  619,  463,  614,   10,  417,  462,  255,
- /*  1040 */   189,  510,  553,  351,  207,  363,  161,  614,   38,  315,
- /*  1050 */   218,  255,  255,   80,  600,  599,  601,  601,   87,   87,
- /*  1060 */    88,   88,   88,   88,  424,   86,   86,   86,   86,   85,
- /*  1070 */    85,   84,   84,   84,   83,  330,   76,  419,  255,    3,
- /*  1080 */   878,  461,  424,  247,  331,  331,  614,   37,  217,   76,
- /*  1090 */   419,  390,    3,  216,  215,  422,    4,  331,  331,  424,
- /*  1100 */   547,   12,  424,  545,  614,   36,  424,  541,  422,  424,
- /*  1110 */   540,  424,  214,  424,  408,  424,  539,  403,  605,  605,
- /*  1120 */   237,  614,   25,  119,  614,   24,  588,  408,  614,   45,
- /*  1130 */   118,  614,   35,  614,   34,  614,   33,  614,   23,  588,
- /*  1140 */    60,  223,  603,  602,  513,  378,   73,   74,  140,  139,
- /*  1150 */   424,  110,  265,   75,  426,  425,   59,  424,  610,   73,
- /*  1160 */    74,  549,  402,  404,  424,  373,   75,  426,  425,  604,
- /*  1170 */   138,  610,  614,   11,  392,   76,  419,  181,    3,  614,
- /*  1180 */    32,  271,  369,  331,  331,  493,  614,   31,  149,  608,
- /*  1190 */   608,  608,  607,   15,  422,  365,  614,    8,  137,  489,
- /*  1200 */   136,  190,  608,  608,  608,  607,   15,  485,  176,  135,
- /*  1210 */     7,  252,  477,  408,  174,  133,  175,  474,   57,   56,
- /*  1220 */   132,  130,  119,   76,  419,  588,    3,  468,  245,  464,
- /*  1230 */   171,  331,  331,  125,  123,  456,  447,  122,  446,  104,
- /*  1240 */   336,  231,  422,  166,  154,   73,   74,  332,  116,  431,
- /*  1250 */   121,  309,   75,  426,  425,  222,  106,  610,  308,  637,
- /*  1260 */   204,  408,  629,  627,  628,    6,  200,  428,  427,  290,
- /*  1270 */   203,  622,  201,  588,   62,   63,  289,   66,  419,  399,
- /*  1280 */     3,  401,  288,   92,  143,  331,  331,  287,  608,  608,
- /*  1290 */   608,  607,   15,   73,   74,  227,  422,  325,   69,  416,
- /*  1300 */    75,  426,  425,  612,  412,  610,  192,   61,  569,  209,
- /*  1310 */   396,  226,  278,  225,  383,  408,  527,  558,  276,  533,
- /*  1320 */   552,  528,  321,  523,  370,  508,  180,  588,  494,  179,
- /*  1330 */   366,  117,  253,  269,  522,  503,  608,  608,  608,  607,
- /*  1340 */    15,  551,  502,   58,  274,  524,  178,   73,   74,  304,
- /*  1350 */   501,  368,  303,  206,   75,  426,  425,  491,  360,  610,
- /*  1360 */   213,  177,  483,  131,  345,  298,  297,  296,  202,  294,
- /*  1370 */   480,  490,  466,  134,  172,  129,  444,  346,  470,  128,
- /*  1380 */   314,  459,  103,  127,  126,  148,  124,  167,  443,  235,
- /*  1390 */   608,  608,  608,  607,   15,  442,  439,  623,  234,  299,
- /*  1400 */   145,  583,  291,  377,  581,  160,  119,  156,  270,  636,
- /*  1410 */   971,  169,  279,  626,  520,  625,  473,  624,  170,  621,
- /*  1420 */   618,  119,  168,   55,  409,  423,  537,  609,  286,  285,
- /*  1430 */   405,  570,  560,  556,    5,   52,  458,  554,  147,  267,
- /*  1440 */   519,  504,  518,  406,  262,  239,  260,  512,  343,  511,
- /*  1450 */   258,  353,  565,  256,  224,  251,  359,  277,  275,  476,
- /*  1460 */   475,  246,  352,  244,  467,  455,  236,  233,  232,  307,
- /*  1470 */   441,  281,  205,  163,  397,  280,  535,  505,  330,  617,
- /*  1480 */   971,  971,  971,  971,  367,  971,  971,  971,  971,  971,
- /*  1490 */   971,  971,  971,  971,  971,  971,  338,
+ /*     0 */   311, 1306,  145,  651,    2,  192,  652,  338,  780,   92,
+ /*    10 */    92,   92,   92,   85,   90,   90,   90,   90,   89,   89,
+ /*    20 */    88,   88,   88,   87,  335,   88,   88,   88,   87,  335,
+ /*    30 */   327,  856,  856,   92,   92,   92,   92,  776,   90,   90,
+ /*    40 */    90,   90,   89,   89,   88,   88,   88,   87,  335,   86,
+ /*    50 */    83,  166,   93,   94,   84,  868,  871,  860,  860,   91,
+ /*    60 */    91,   92,   92,   92,   92,  335,   90,   90,   90,   90,
+ /*    70 */    89,   89,   88,   88,   88,   87,  335,  311,  780,   90,
+ /*    80 */    90,   90,   90,   89,   89,   88,   88,   88,   87,  335,
+ /*    90 */   123,  808,  689,  689,  689,  689,  112,  230,  430,  257,
+ /*   100 */   809,  698,  430,   86,   83,  166,  324,   55,  856,  856,
+ /*   110 */   201,  158,  276,  387,  271,  386,  188,  689,  689,  828,
+ /*   120 */   833,   49,  944,  269,  833,   49,  123,   87,  335,   93,
+ /*   130 */    94,   84,  868,  871,  860,  860,   91,   91,   92,   92,
+ /*   140 */    92,   92,  342,   90,   90,   90,   90,   89,   89,   88,
+ /*   150 */    88,   88,   87,  335,  311,  328,  333,  332,  701,  408,
+ /*   160 */   394,   69,  690,  691,  690,  691,  715,  910,  251,  354,
+ /*   170 */   250,  698,  704,  430,  908,  430,  909,   89,   89,   88,
+ /*   180 */    88,   88,   87,  335,  391,  856,  856,  690,  691,  183,
+ /*   190 */    95,  340,  384,  381,  380,  833,   31,  833,   49,  912,
+ /*   200 */   912,  333,  332,  379,  123,  311,   93,   94,   84,  868,
+ /*   210 */   871,  860,  860,   91,   91,   92,   92,   92,   92,  114,
+ /*   220 */    90,   90,   90,   90,   89,   89,   88,   88,   88,   87,
+ /*   230 */   335,  430,  408,  399,  435,  657,  856,  856,  346,   57,
+ /*   240 */   232,  828,  109,   20,  912,  912,  231,  393,  937,  760,
+ /*   250 */    97,  751,  752,  833,   49,  708,  708,   93,   94,   84,
+ /*   260 */   868,  871,  860,  860,   91,   91,   92,   92,   92,   92,
+ /*   270 */   707,   90,   90,   90,   90,   89,   89,   88,   88,   88,
+ /*   280 */    87,  335,  311,  114,   22,  706,  688,   58,  408,  390,
+ /*   290 */   251,  349,  240,  749,  752,  689,  689,  847,  685,  115,
+ /*   300 */    21,  231,  393,  689,  689,  697,  183,  355,  430,  384,
+ /*   310 */   381,  380,  192,  856,  856,  780,  123,  160,  159,  223,
+ /*   320 */   379,  738,   25,  315,  362,  841,  143,  689,  689,  835,
+ /*   330 */   833,   48,  339,  937,   93,   94,   84,  868,  871,  860,
+ /*   340 */   860,   91,   91,   92,   92,   92,   92,  914,   90,   90,
+ /*   350 */    90,   90,   89,   89,   88,   88,   88,   87,  335,  311,
+ /*   360 */   840,  840,  840,  266,  430,  690,  691,  778,  114, 1300,
+ /*   370 */  1300,  430,    1,  690,  691,  697,  688,  689,  689,  689,
+ /*   380 */   689,  689,  689,  287,  298,  780,  833,   10,  686,  115,
+ /*   390 */   856,  856,  355,  833,   10,  828,  366,  690,  691,  363,
+ /*   400 */   321,   76,  123,   74,   23,  737,  807,  323,  356,  353,
+ /*   410 */   847,   93,   94,   84,  868,  871,  860,  860,   91,   91,
+ /*   420 */    92,   92,   92,   92,  940,   90,   90,   90,   90,   89,
+ /*   430 */    89,   88,   88,   88,   87,  335,  311,  806,  841,  429,
+ /*   440 */   713,  941,  835,  430,  251,  354,  250,  690,  691,  690,
+ /*   450 */   691,  690,  691,   86,   83,  166,   24,  942,  151,  753,
+ /*   460 */   285,  907,  403,  907,  164,  833,   10,  856,  856,  965,
+ /*   470 */   306,  754,  679,  840,  840,  840,  795,  216,  794,  222,
+ /*   480 */   906,  344,  906,  904,   86,   83,  166,  286,   93,   94,
+ /*   490 */    84,  868,  871,  860,  860,   91,   91,   92,   92,   92,
+ /*   500 */    92,  430,   90,   90,   90,   90,   89,   89,   88,   88,
+ /*   510 */    88,   87,  335,  311,  430,  724,  352,  705,  427,  699,
+ /*   520 */   700,  376,  210,  833,   49,  793,  397,  857,  857,  940,
+ /*   530 */   213,  762,  727,  334,  699,  700,  833,   10,   86,   83,
+ /*   540 */   166,  345,  396,  902,  856,  856,  941,  385,  833,    9,
+ /*   550 */   406,  869,  872,  187,  890,  728,  347,  398,  404,  977,
+ /*   560 */   652,  338,  942,  954,  413,   93,   94,   84,  868,  871,
+ /*   570 */   860,  860,   91,   91,   92,   92,   92,   92,  861,   90,
+ /*   580 */    90,   90,   90,   89,   89,   88,   88,   88,   87,  335,
+ /*   590 */   311, 1219,  114,  430,  834,  430,    5,  165,  192,  688,
+ /*   600 */   832,  780,  430,  723,  430,  234,  325,  189,  163,  316,
+ /*   610 */   356,  955,  115,  235,  269,  833,   35,  833,   36,  747,
+ /*   620 */   720,  856,  856,  793,  833,   12,  833,   27,  745,  174,
+ /*   630 */   968, 1290,  968, 1291, 1290,  310, 1291,  693,  317,  245,
+ /*   640 */   264,  311,   93,   94,   84,  868,  871,  860,  860,   91,
+ /*   650 */    91,   92,   92,   92,   92,  832,   90,   90,   90,   90,
+ /*   660 */    89,   89,   88,   88,   88,   87,  335,  430,  320,  213,
+ /*   670 */   762,  780,  856,  856,  920,  920,  369,  257,  966,  220,
+ /*   680 */   966,  396,  663,  664,  665,  242,  259,  244,  262,  833,
+ /*   690 */    37,  650,    2,   93,   94,   84,  868,  871,  860,  860,
+ /*   700 */    91,   91,   92,   92,   92,   92,  430,   90,   90,   90,
+ /*   710 */    90,   89,   89,   88,   88,   88,   87,  335,  311,  430,
+ /*   720 */   239,  430,  917,  368,  430,  238,  916,  793,  833,   38,
+ /*   730 */   430,  825,  430,   66,  430,  392,  430,  766,  766,  430,
+ /*   740 */   367,  833,   39,  833,   28,  430,  833,   29,   68,  856,
+ /*   750 */   856,  900,  833,   40,  833,   41,  833,   42,  833,   11,
+ /*   760 */    72,  833,   43,  243,  305,  970,  114,  833,   99,  961,
+ /*   770 */    93,   94,   84,  868,  871,  860,  860,   91,   91,   92,
+ /*   780 */    92,   92,   92,  430,   90,   90,   90,   90,   89,   89,
+ /*   790 */    88,   88,   88,   87,  335,  311,  430,  361,  430,  165,
+ /*   800 */   147,  430,  186,  185,  184,  833,   44,  430,  289,  430,
+ /*   810 */   246,  430,  971,  430,  212,  163,  430,  357,  833,   45,
+ /*   820 */   833,   32,  932,  833,   46,  793,  856,  856,  718,  833,
+ /*   830 */    47,  833,   33,  833,  117,  833,  118,   75,  833,  119,
+ /*   840 */   288,  305,  967,  214,  935,  322,  311,   93,   94,   84,
+ /*   850 */   868,  871,  860,  860,   91,   91,   92,   92,   92,   92,
+ /*   860 */   430,   90,   90,   90,   90,   89,   89,   88,   88,   88,
+ /*   870 */    87,  335,  430,  832,  426,  317,  288,  856,  856,  114,
+ /*   880 */   763,  257,  833,   53,  930,  219,  364,  257,  257,  971,
+ /*   890 */   361,  396,  257,  257,  833,   34,  257,  311,   93,   94,
+ /*   900 */    84,  868,  871,  860,  860,   91,   91,   92,   92,   92,
+ /*   910 */    92,  430,   90,   90,   90,   90,   89,   89,   88,   88,
+ /*   920 */    88,   87,  335,  430,  217,  318,  124,  253,  856,  856,
+ /*   930 */   218,  943,  257,  833,  100,  898,  759,  774,  361,  755,
+ /*   940 */   423,  329,  758, 1017,  289,  833,   50,  682,  311,   93,
+ /*   950 */    82,   84,  868,  871,  860,  860,   91,   91,   92,   92,
+ /*   960 */    92,   92,  430,   90,   90,   90,   90,   89,   89,   88,
+ /*   970 */    88,   88,   87,  335,  430,  256,  419,  114,  249,  856,
+ /*   980 */   856,  331,  114,  400,  833,  101,  359,  187, 1064,  726,
+ /*   990 */   725,  739,  401,  416,  420,  360,  833,  102,  424,  311,
+ /*  1000 */   258,   94,   84,  868,  871,  860,  860,   91,   91,   92,
+ /*  1010 */    92,   92,   92,  430,   90,   90,   90,   90,   89,   89,
+ /*  1020 */    88,   88,   88,   87,  335,  430,  221,  261,  114,  114,
+ /*  1030 */   856,  856,  808,  114,  156,  833,   98,  772,  733,  734,
+ /*  1040 */   275,  809,  771,  316,  263,  265,  960,  833,  116,  307,
+ /*  1050 */   741,  274,  722,   84,  868,  871,  860,  860,   91,   91,
+ /*  1060 */    92,   92,   92,   92,  430,   90,   90,   90,   90,   89,
+ /*  1070 */    89,   88,   88,   88,   87,  335,   80,  425,  830,    3,
+ /*  1080 */  1214,  191,  430,  721,  336,  336,  833,  113,  252,   80,
+ /*  1090 */   425,   68,    3,  913,  913,  428,  270,  336,  336,  430,
+ /*  1100 */   377,  784,  430,  197,  833,  106,  430,  716,  428,  430,
+ /*  1110 */   267,  430,  897,   68,  414,  430,  769,  409,  430,   71,
+ /*  1120 */   430,  833,  105,  123,  833,  103,  847,  414,  833,   49,
+ /*  1130 */   843,  833,  104,  833,   52,  800,  123,  833,   54,  847,
+ /*  1140 */   833,   51,  833,   26,  831,  802,   77,   78,  191,  389,
+ /*  1150 */   430,  372,  114,   79,  432,  431,  911,  911,  835,   77,
+ /*  1160 */    78,  779,  893,  408,  410,  197,   79,  432,  431,  791,
+ /*  1170 */   226,  835,  833,   30,  772,   80,  425,  716,    3,  771,
+ /*  1180 */   411,  412,  897,  336,  336,  290,  291,  839,  703,  840,
+ /*  1190 */   840,  840,  842,   19,  428,  695,  684,  672,  111,  671,
+ /*  1200 */   843,  673,  840,  840,  840,  842,   19,  207,  661,  278,
+ /*  1210 */   148,  304,  280,  414,  282,    6,  822,  348,  248,  241,
+ /*  1220 */   358,  934,  720,   80,  425,  847,    3,  161,  382,  273,
+ /*  1230 */   284,  336,  336,  415,  296,  958,  895,  894,  157,  674,
+ /*  1240 */   107,  194,  428,  948,  135,   77,   78,  777,  953,  951,
+ /*  1250 */    56,  319,   79,  432,  431,  121,   66,  835,   59,  128,
+ /*  1260 */   146,  414,  350,  130,  351,  819,  131,  132,  133,  375,
+ /*  1270 */   173,  149,  138,  847,  936,  365,  178,   70,  425,  827,
+ /*  1280 */     3,  889,   62,  371,  915,  336,  336,  792,  840,  840,
+ /*  1290 */   840,  842,   19,   77,   78,  208,  428,  144,  179,  373,
+ /*  1300 */    79,  432,  431,  255,  180,  835,  260,  675,  181,  308,
+ /*  1310 */   388,  744,  326,  743,  742,  414,  731,  718,  712,  402,
+ /*  1320 */   309,  711,  788,   65,  277,  272,  789,  847,  730,  710,
+ /*  1330 */   709,  279,  193,  787,  281,  876,  840,  840,  840,  842,
+ /*  1340 */    19,  786,  283,   73,  418,  330,  422,   77,   78,  227,
+ /*  1350 */    96,  407,   67,  405,   79,  432,  431,  292,  228,  835,
+ /*  1360 */   215,  202,  229,  293,  767,  303,  302,  301,  204,  299,
+ /*  1370 */   294,  295,  676,    7,  681,  433,  669,  206,  110,  224,
+ /*  1380 */   203,  205,  434,  667,  666,  658,  120,  168,  656,  237,
+ /*  1390 */   840,  840,  840,  842,   19,  337,  155,  233,  236,  341,
+ /*  1400 */   167,  905,  108,  313,  903,  826,  314,  125,  126,  127,
+ /*  1410 */   129,  170,  247,  756,  172,  928,  134,  136,  171,   60,
+ /*  1420 */    61,  123,  169,  137,  175,  933,  176,  927,    8,   13,
+ /*  1430 */   177,  254,  191,  918,  139,  370,  924,  140,  678,  150,
+ /*  1440 */   374,  274,  182,  378,  141,  122,   63,   14,  383,  729,
+ /*  1450 */   268,   15,   64,  225,  846,  845,  874,   16,  765,  770,
+ /*  1460 */     4,  162,  209,  395,  211,  142,  878,  796,  801,  312,
+ /*  1470 */   190,   71,   68,  875,  873,  939,  199,  938,   17,  195,
+ /*  1480 */    18,  196,  417,  975,  152,  653,  976,  198,  153,  421,
+ /*  1490 */   877,  154,  200,  844,  696,   81,  343,  297, 1019, 1018,
+ /*  1500 */   300,
 };
 static const YYCODETYPE yy_lookahead[] = {
- /*     0 */    19,   22,   22,   23,    1,   24,   26,   15,   27,   80,
+ /*     0 */    19,  144,  145,  146,  147,   24,    1,    2,   27,   80,
  /*    10 */    81,   82,   83,   84,   85,   86,   87,   88,   89,   90,
- /*    20 */    91,   92,   93,   94,   95,  108,  109,  110,   27,   28,
- /*    30 */    23,   50,   51,   80,   81,   82,   83,  122,   85,   86,
- /*    40 */    87,   88,   89,   90,   91,   92,   93,   94,   95,   22,
- /*    50 */    70,   23,   71,   72,   73,   74,   75,   76,   77,   78,
- /*    60 */    79,   80,   81,   82,   83,  122,   85,   86,   87,   88,
- /*    70 */    89,   90,   91,   92,   93,   94,   95,   19,   97,   91,
- /*    80 */    92,   93,   94,   95,   26,   85,   86,   87,   88,   89,
- /*    90 */    90,   91,   92,   93,   94,   95,   27,   28,   97,   98,
- /*   100 */    99,  122,  211,  102,  103,  104,   79,   19,   50,   51,
- /*   110 */    19,  122,   59,   55,  113,  224,  225,  226,   89,   90,
- /*   120 */    91,   92,   93,   94,   95,   23,   27,   28,   26,   71,
+ /*    20 */    91,   92,   93,   94,   95,   91,   92,   93,   94,   95,
+ /*    30 */    19,   50,   51,   80,   81,   82,   83,  212,   85,   86,
+ /*    40 */    87,   88,   89,   90,   91,   92,   93,   94,   95,  224,
+ /*    50 */   225,  226,   71,   72,   73,   74,   75,   76,   77,   78,
+ /*    60 */    79,   80,   81,   82,   83,   95,   85,   86,   87,   88,
+ /*    70 */    89,   90,   91,   92,   93,   94,   95,   19,   97,   85,
+ /*    80 */    86,   87,   88,   89,   90,   91,   92,   93,   94,   95,
+ /*    90 */    66,   33,   27,   28,   27,   28,   22,  201,  152,  152,
+ /*   100 */    42,   27,  152,  224,  225,  226,   95,  211,   50,   51,
+ /*   110 */    99,  100,  101,  102,  103,  104,  105,   27,   28,   59,
+ /*   120 */   174,  175,  243,  112,  174,  175,   66,   94,   95,   71,
  /*   130 */    72,   73,   74,   75,   76,   77,   78,   79,   80,   81,
- /*   140 */    82,   83,   51,   85,   86,   87,   88,   89,   90,   91,
- /*   150 */    92,   93,   94,   95,   19,  132,  133,   58,   89,   90,
- /*   160 */    21,  108,  109,  110,   27,   28,   97,   98,   33,  100,
- /*   170 */     7,    8,  119,  120,   22,   19,  107,   42,  109,   27,
- /*   180 */    28,   27,   28,   95,   28,   50,   51,   99,  100,  101,
- /*   190 */   102,  103,  104,  105,   27,   28,   97,   98,  107,  152,
- /*   200 */   112,  132,  133,  112,   65,   69,   71,   72,   73,   74,
- /*   210 */    75,   76,   77,   78,   79,   80,   81,   82,   83,   11,
+ /*   140 */    82,   83,  195,   85,   86,   87,   88,   89,   90,   91,
+ /*   150 */    92,   93,   94,   95,   19,  209,   89,   90,  173,  209,
+ /*   160 */   210,   26,   97,   98,   97,   98,  181,  100,  108,  109,
+ /*   170 */   110,   97,  174,  152,  107,  152,  109,   89,   90,   91,
+ /*   180 */    92,   93,   94,   95,  163,   50,   51,   97,   98,   99,
+ /*   190 */    55,  244,  102,  103,  104,  174,  175,  174,  175,  132,
+ /*   200 */   133,   89,   90,  113,   66,   19,   71,   72,   73,   74,
+ /*   210 */    75,   76,   77,   78,   79,   80,   81,   82,   83,  198,
  /*   220 */    85,   86,   87,   88,   89,   90,   91,   92,   93,   94,
- /*   230 */    95,   19,  101,   97,   97,   98,   24,  101,  122,  157,
- /*   240 */    12,   99,  103,  112,  102,  103,  104,  152,   22,   97,
- /*   250 */    98,   97,   98,   27,   28,  113,   27,   29,   91,  164,
- /*   260 */   165,  124,   50,   51,   97,   98,  219,   59,  132,  133,
- /*   270 */   134,   22,   23,   45,   66,   47,  212,  213,  124,  140,
- /*   280 */   132,  133,   19,   71,   72,   73,   74,   75,   76,   77,
- /*   290 */    78,   79,   80,   81,   82,   83,  152,   85,   86,   87,
- /*   300 */    88,   89,   90,   91,   92,   93,   94,   95,  164,  165,
- /*   310 */    27,   28,  230,   50,   51,  233,  108,  109,  110,   70,
- /*   320 */    16,   59,   23,   97,   98,   26,   97,   22,   66,  185,
- /*   330 */    12,  187,   27,   28,   71,   72,   73,   74,   75,   76,
- /*   340 */    77,   78,   79,   80,   81,   82,   83,   29,   85,   86,
+ /*   230 */    95,  152,  209,  210,  148,  149,   50,   51,  100,   53,
+ /*   240 */   154,   59,  156,   22,  132,  133,  119,  120,  163,  163,
+ /*   250 */    22,  192,  193,  174,  175,   27,   28,   71,   72,   73,
+ /*   260 */    74,   75,   76,   77,   78,   79,   80,   81,   82,   83,
+ /*   270 */   174,   85,   86,   87,   88,   89,   90,   91,   92,   93,
+ /*   280 */    94,   95,   19,  198,  198,  174,  152,   24,  209,  210,
+ /*   290 */   108,  109,  110,  192,  193,   27,   28,   69,  164,  165,
+ /*   300 */    79,  119,  120,   27,   28,   27,   99,  222,  152,  102,
+ /*   310 */   103,  104,   24,   50,   51,   27,   66,   89,   90,  185,
+ /*   320 */   113,  187,   22,  157,  239,   97,   58,   27,   28,  101,
+ /*   330 */   174,  175,  246,  163,   71,   72,   73,   74,   75,   76,
+ /*   340 */    77,   78,   79,   80,   81,   82,   83,   11,   85,   86,
  /*   350 */    87,   88,   89,   90,   91,   92,   93,   94,   95,   19,
- /*   360 */    22,  148,  149,   45,   23,   47,   62,  154,   64,  156,
- /*   370 */   108,  109,  110,   37,   69,   23,  163,   59,   26,   26,
- /*   380 */    97,   98,  144,  145,  146,  147,  152,  200,   52,   23,
- /*   390 */    50,   51,   26,   22,   89,   90,   60,  210,    7,    8,
- /*   400 */     9,  138,   97,   22,   23,   26,  101,   26,  174,  175,
- /*   410 */   197,   71,   72,   73,   74,   75,   76,   77,   78,   79,
- /*   420 */    80,   81,   82,   83,   16,   85,   86,   87,   88,   89,
- /*   430 */    90,   91,   92,   93,   94,   95,   19,  132,  133,  134,
- /*   440 */    23,  152,  208,  209,  140,  152,  152,  111,  195,  196,
- /*   450 */    98,   70,  163,  160,  152,   23,   22,  164,  165,  246,
- /*   460 */   207,   27,  152,  174,  175,  171,  172,   50,   51,  137,
- /*   470 */    62,  139,   64,  171,  172,  222,  124,   27,  138,   24,
- /*   480 */   163,   89,   90,  130,  174,  175,  197,  163,   71,   72,
+ /*   360 */   132,  133,  134,   23,  152,   97,   98,   91,  198,  119,
+ /*   370 */   120,  152,   22,   97,   98,   97,  152,   27,   28,   27,
+ /*   380 */    28,   27,   28,  227,  160,   97,  174,  175,  164,  165,
+ /*   390 */    50,   51,  222,  174,  175,   59,  230,   97,   98,  233,
+ /*   400 */   188,  137,   66,  139,  234,  187,  177,  188,  152,  239,
+ /*   410 */    69,   71,   72,   73,   74,   75,   76,   77,   78,   79,
+ /*   420 */    80,   81,   82,   83,   12,   85,   86,   87,   88,   89,
+ /*   430 */    90,   91,   92,   93,   94,   95,   19,  177,   97,  152,
+ /*   440 */    23,   29,  101,  152,  108,  109,  110,   97,   98,   97,
+ /*   450 */    98,   97,   98,  224,  225,  226,   22,   45,   24,   47,
+ /*   460 */   152,  152,  152,  152,  152,  174,  175,   50,   51,  249,
+ /*   470 */   250,   59,   21,  132,  133,  134,  124,  221,  124,  188,
+ /*   480 */   171,  172,  171,  172,  224,  225,  226,  152,   71,   72,
  /*   490 */    73,   74,   75,   76,   77,   78,   79,   80,   81,   82,
- /*   500 */    83,   22,   85,   86,   87,   88,   89,   90,   91,   92,
- /*   510 */    93,   94,   95,   19,  197,  181,  182,   23,  208,  209,
- /*   520 */   152,  197,   26,  189,  132,  133,  232,  224,  225,  226,
- /*   530 */   152,   97,   91,   26,  232,  116,  212,  213,  152,  222,
- /*   540 */   121,  152,  174,  175,   50,   51,  243,   97,   22,   23,
- /*   550 */    22,  234,  174,  175,  177,   23,  239,  116,  163,  177,
- /*   560 */   174,  175,  121,  174,  175,   71,   72,   73,   74,   75,
- /*   570 */    76,   77,   78,   79,   80,   81,   82,   83,   24,   85,
+ /*   500 */    83,  152,   85,   86,   87,   88,   89,   90,   91,   92,
+ /*   510 */    93,   94,   95,   19,  152,  183,   65,   23,  170,  171,
+ /*   520 */   172,   19,   23,  174,  175,   26,  152,   50,   51,   12,
+ /*   530 */   196,  197,   37,  170,  171,  172,  174,  175,  224,  225,
+ /*   540 */   226,  232,  208,  232,   50,   51,   29,   52,  174,  175,
+ /*   550 */   188,   74,   75,   51,  103,   60,  222,  163,  209,    0,
+ /*   560 */     1,    2,   45,  152,   47,   71,   72,   73,   74,   75,
+ /*   570 */    76,   77,   78,   79,   80,   81,   82,   83,  101,   85,
  /*   580 */    86,   87,   88,   89,   90,   91,   92,   93,   94,   95,
- /*   590 */    19,   23,  197,   11,   23,  227,   70,  208,  220,  152,
- /*   600 */    31,  224,  225,  226,   35,   98,  224,  225,  226,  108,
- /*   610 */   109,  110,  115,  152,  117,  118,   27,  222,   49,  123,
- /*   620 */    24,   50,   51,   27,    0,    1,    2,  224,  225,  226,
- /*   630 */   166,  124,  168,  169,  239,  174,  175,  170,  171,  172,
- /*   640 */    22,  194,   71,   72,   73,   74,   75,   76,   77,   78,
+ /*   590 */    19,  140,  198,  152,   23,  152,   22,   98,   24,  152,
+ /*   600 */   152,   27,  152,  183,  152,  152,  111,  213,  214,  107,
+ /*   610 */   152,  164,  165,  152,  112,  174,  175,  174,  175,  181,
+ /*   620 */   182,   50,   51,  124,  174,  175,  174,  175,  190,   26,
+ /*   630 */    22,   23,   22,   23,   26,  166,   26,  168,  169,   16,
+ /*   640 */    16,   19,   71,   72,   73,   74,   75,   76,   77,   78,
  /*   650 */    79,   80,   81,   82,   83,  152,   85,   86,   87,   88,
- /*   660 */    89,   90,   91,   92,   93,   94,   95,   19,   22,  208,
- /*   670 */    24,   23,  195,  196,  170,  171,  172,  174,  175,  152,
- /*   680 */    26,  152,  152,  152,  207,  152,   97,  152,   23,  152,
- /*   690 */    51,  244,  152,   97,  152,  247,  248,   23,   50,   51,
- /*   700 */    26,  174,  175,  174,  175,  174,  175,  174,  175,  174,
- /*   710 */   175,  174,  175,   23,  174,  175,  174,  175,  188,   71,
- /*   720 */    72,   73,   74,   75,   76,   77,   78,   79,   80,   81,
- /*   730 */    82,   83,  152,   85,   86,   87,   88,   89,   90,   91,
- /*   740 */    92,   93,   94,   95,   19,  152,  107,  152,   33,   24,
- /*   750 */   152,  100,  101,   27,  174,  175,  152,   42,  152,   23,
- /*   760 */   152,   26,  152,   23,  152,   26,  152,  174,  175,  174,
- /*   770 */   175,  152,  174,  175,   23,   50,   51,   26,  174,  175,
- /*   780 */   174,  175,  174,  175,  174,  175,  174,  175,  174,  175,
- /*   790 */   163,  119,  120,  174,  175,   19,   71,   72,   73,   74,
- /*   800 */    75,   76,   77,   78,   79,   80,   81,   82,   83,  152,
- /*   810 */    85,   86,   87,   88,   89,   90,   91,   92,   93,   94,
- /*   820 */    95,   66,  152,   97,  197,   23,   50,   51,   26,   53,
- /*   830 */    23,  174,  175,   26,   23,   23,   23,   26,   26,   26,
- /*   840 */    36,  106,  146,  147,  174,  175,   19,   71,   72,   73,
+ /*   660 */    89,   90,   91,   92,   93,   94,   95,  152,  220,  196,
+ /*   670 */   197,   97,   50,   51,  108,  109,  110,  152,   70,  221,
+ /*   680 */    70,  208,    7,    8,    9,   62,   62,   64,   64,  174,
+ /*   690 */   175,  146,  147,   71,   72,   73,   74,   75,   76,   77,
+ /*   700 */    78,   79,   80,   81,   82,   83,  152,   85,   86,   87,
+ /*   710 */    88,   89,   90,   91,   92,   93,   94,   95,   19,  152,
+ /*   720 */   195,  152,   31,  220,  152,  152,   35,   26,  174,  175,
+ /*   730 */   152,  163,  152,  130,  152,  115,  152,  117,  118,  152,
+ /*   740 */    49,  174,  175,  174,  175,  152,  174,  175,   26,   50,
+ /*   750 */    51,  152,  174,  175,  174,  175,  174,  175,  174,  175,
+ /*   760 */   138,  174,  175,  140,   22,   23,  198,  174,  175,  152,
+ /*   770 */    71,   72,   73,   74,   75,   76,   77,   78,   79,   80,
+ /*   780 */    81,   82,   83,  152,   85,   86,   87,   88,   89,   90,
+ /*   790 */    91,   92,   93,   94,   95,   19,  152,  152,  152,   98,
+ /*   800 */    24,  152,  108,  109,  110,  174,  175,  152,  152,  152,
+ /*   810 */   152,  152,   70,  152,  213,  214,  152,  152,  174,  175,
+ /*   820 */   174,  175,  152,  174,  175,  124,   50,   51,  106,  174,
+ /*   830 */   175,  174,  175,  174,  175,  174,  175,  138,  174,  175,
+ /*   840 */   152,   22,   23,   22,  163,  189,   19,   71,   72,   73,
  /*   850 */    74,   75,   76,   77,   78,   79,   80,   81,   82,   83,
  /*   860 */   152,   85,   86,   87,   88,   89,   90,   91,   92,   93,
- /*   870 */    94,   95,  152,  196,  119,  120,   19,   50,   51,  168,
- /*   880 */   169,   26,  174,  175,  207,   28,  152,  249,  250,  152,
- /*   890 */   163,  163,  163,  163,  174,  175,  163,   19,   71,   72,
+ /*   870 */    94,   95,  152,  152,  168,  169,  152,   50,   51,  198,
+ /*   880 */   197,  152,  174,  175,  152,  240,  152,  152,  152,   70,
+ /*   890 */   152,  208,  152,  152,  174,  175,  152,   19,   71,   72,
  /*   900 */    73,   74,   75,   76,   77,   78,   79,   80,   81,   82,
  /*   910 */    83,  152,   85,   86,   87,   88,   89,   90,   91,   92,
- /*   920 */    93,   94,   95,  152,  197,  197,  197,  197,   50,   51,
- /*   930 */   197,  194,   36,  174,  175,  191,  192,  152,  191,  192,
- /*   940 */   163,  152,   66,  124,  152,  174,  175,  152,   19,   71,
+ /*   920 */    93,   94,   95,  152,  195,  247,  248,  152,   50,   51,
+ /*   930 */   195,  195,  152,  174,  175,  195,  195,   26,  152,  195,
+ /*   940 */   252,  220,  163,  122,  152,  174,  175,  163,   19,   71,
  /*   950 */    72,   73,   74,   75,   76,   77,   78,   79,   80,   81,
  /*   960 */    82,   83,  152,   85,   86,   87,   88,   89,   90,   91,
- /*   970 */    92,   93,   94,   95,  197,  152,  100,  188,  152,   50,
- /*   980 */    51,  152,  152,  188,  174,  175,  252,  152,   94,   95,
- /*   990 */   152,  152,  152,    1,    2,  152,  152,  174,  175,   19,
+ /*   970 */    92,   93,   94,   95,  152,  195,  252,  198,  240,   50,
+ /*   980 */    51,  189,  198,   19,  174,  175,   19,   51,   23,  100,
+ /*   990 */   101,   26,   28,  163,  163,   28,  174,  175,  163,   19,
  /*  1000 */   152,   72,   73,   74,   75,   76,   77,   78,   79,   80,
  /*  1010 */    81,   82,   83,  152,   85,   86,   87,   88,   89,   90,
- /*  1020 */    91,   92,   93,   94,   95,  152,  188,  188,   22,  194,
- /*  1030 */    50,   51,  240,  173,  194,  174,  175,  252,  194,  152,
- /*  1040 */    36,  181,   28,  152,   23,  219,  122,  174,  175,  219,
- /*  1050 */   221,  152,  152,   73,   74,   75,   76,   77,   78,   79,
+ /*  1020 */    91,   92,   93,   94,   95,  152,  240,  152,  198,  198,
+ /*  1030 */    50,   51,   33,  198,  123,  174,  175,  116,    7,    8,
+ /*  1040 */   101,   42,  121,  107,  152,  152,   23,  174,  175,   26,
+ /*  1050 */   152,  112,  183,   73,   74,   75,   76,   77,   78,   79,
  /*  1060 */    80,   81,   82,   83,  152,   85,   86,   87,   88,   89,
- /*  1070 */    90,   91,   92,   93,   94,   95,   19,   20,  152,   22,
- /*  1080 */    23,  194,  152,  240,   27,   28,  174,  175,  240,   19,
- /*  1090 */    20,   26,   22,  194,  194,   38,   22,   27,   28,  152,
- /*  1100 */    23,   22,  152,  116,  174,  175,  152,   23,   38,  152,
- /*  1110 */    23,  152,  221,  152,   57,  152,   23,  163,   50,   51,
- /*  1120 */   194,  174,  175,   66,  174,  175,   69,   57,  174,  175,
- /*  1130 */    40,  174,  175,  174,  175,  174,  175,  174,  175,   69,
- /*  1140 */    22,   53,   74,   75,   30,   53,   89,   90,   22,   22,
- /*  1150 */   152,  197,   23,   96,   97,   98,   22,  152,  101,   89,
- /*  1160 */    90,   91,  208,  209,  152,   53,   96,   97,   98,  101,
- /*  1170 */    22,  101,  174,  175,  152,   19,   20,  105,   22,  174,
- /*  1180 */   175,  112,   19,   27,   28,   20,  174,  175,   24,  132,
- /*  1190 */   133,  134,  135,  136,   38,   44,  174,  175,  107,   61,
- /*  1200 */    54,   26,  132,  133,  134,  135,  136,   54,  107,   22,
- /*  1210 */     5,  140,    1,   57,   36,  111,  122,   28,   79,   79,
- /*  1220 */   131,  123,   66,   19,   20,   69,   22,    1,   16,   20,
- /*  1230 */   125,   27,   28,  123,  111,  120,   23,  131,   23,   16,
- /*  1240 */    68,  142,   38,   15,   22,   89,   90,    3,  167,    4,
- /*  1250 */   248,  251,   96,   97,   98,  180,  180,  101,  251,  151,
- /*  1260 */     6,   57,  151,   13,  151,   26,   25,  151,  161,  202,
- /*  1270 */   153,  162,  153,   69,  130,  128,  203,   19,   20,  127,
- /*  1280 */    22,  126,  204,  129,   22,   27,   28,  205,  132,  133,
- /*  1290 */   134,  135,  136,   89,   90,  231,   38,   95,  137,  179,
- /*  1300 */    96,   97,   98,  206,  179,  101,  122,  107,  159,  159,
- /*  1310 */   125,  231,  216,  228,  107,   57,  184,  217,  216,  176,
- /*  1320 */   217,  176,   48,  106,   18,  184,  158,   69,  159,  158,
- /*  1330 */    46,   71,  237,  176,  176,  176,  132,  133,  134,  135,
- /*  1340 */   136,  217,  176,  137,  216,  178,  158,   89,   90,  179,
- /*  1350 */   176,  159,  179,  159,   96,   97,   98,  159,  159,  101,
- /*  1360 */     5,  158,  202,   22,   18,   10,   11,   12,   13,   14,
- /*  1370 */   190,  238,   17,  190,  158,  193,   41,  159,  202,  193,
- /*  1380 */   159,  202,  245,  193,  193,  223,  190,   32,  159,   34,
- /*  1390 */   132,  133,  134,  135,  136,  159,   39,  155,   43,  150,
- /*  1400 */   223,  177,  201,  178,  177,  186,   66,  199,  177,  152,
- /*  1410 */   253,   56,  215,  152,  182,  152,  202,  152,   63,  152,
- /*  1420 */   152,   66,   67,  242,  229,  152,  174,  152,  152,  152,
- /*  1430 */   152,  152,  152,  152,  199,  242,  202,  152,  198,  152,
- /*  1440 */   152,  152,  183,  192,  152,  215,  152,  183,  215,  183,
- /*  1450 */   152,  241,  214,  152,  211,  152,  152,  211,  211,  152,
- /*  1460 */   152,  241,  152,  152,  152,  152,  152,  152,  152,  114,
- /*  1470 */   152,  152,  235,  152,  152,  152,  174,  187,   95,  174,
- /*  1480 */   253,  253,  253,  253,  236,  253,  253,  253,  253,  253,
- /*  1490 */   253,  253,  253,  253,  253,  253,  141,
+ /*  1070 */    90,   91,   92,   93,   94,   95,   19,   20,   23,   22,
+ /*  1080 */    23,   26,  152,  152,   27,   28,  174,  175,   23,   19,
+ /*  1090 */    20,   26,   22,  132,  133,   38,  152,   27,   28,  152,
+ /*  1100 */    23,  215,  152,   26,  174,  175,  152,   27,   38,  152,
+ /*  1110 */    23,  152,   27,   26,   57,  152,   23,  163,  152,   26,
+ /*  1120 */   152,  174,  175,   66,  174,  175,   69,   57,  174,  175,
+ /*  1130 */    27,  174,  175,  174,  175,  152,   66,  174,  175,   69,
+ /*  1140 */   174,  175,  174,  175,  152,   23,   89,   90,   26,   91,
+ /*  1150 */   152,  236,  198,   96,   97,   98,  132,  133,  101,   89,
+ /*  1160 */    90,  152,   23,  209,  210,   26,   96,   97,   98,  152,
+ /*  1170 */   212,  101,  174,  175,  116,   19,   20,   97,   22,  121,
+ /*  1180 */   152,  193,   97,   27,   28,  152,  152,  152,  152,  132,
+ /*  1190 */   133,  134,  135,  136,   38,   23,  152,  152,   26,  152,
+ /*  1200 */    97,  152,  132,  133,  134,  135,  136,  235,  152,  212,
+ /*  1210 */   199,  150,  212,   57,  212,  200,  203,  216,  241,  216,
+ /*  1220 */   241,  203,  182,   19,   20,   69,   22,  186,  178,  177,
+ /*  1230 */   216,   27,   28,  229,  202,   39,  177,  177,  200,  155,
+ /*  1240 */   245,  122,   38,   41,   22,   89,   90,   91,  159,  159,
+ /*  1250 */   242,  159,   96,   97,   98,   71,  130,  101,  242,  191,
+ /*  1260 */   223,   57,   18,  194,  159,  203,  194,  194,  194,   18,
+ /*  1270 */   158,  223,  191,   69,  203,  159,  158,   19,   20,  191,
+ /*  1280 */    22,  203,  137,   46,  238,   27,   28,  159,  132,  133,
+ /*  1290 */   134,  135,  136,   89,   90,  159,   38,   22,  158,  179,
+ /*  1300 */    96,   97,   98,  237,  158,  101,  159,  159,  158,  179,
+ /*  1310 */   107,  176,   48,  176,  176,   57,  184,  106,  176,  125,
+ /*  1320 */   179,  178,  218,  107,  217,  176,  218,   69,  184,  176,
+ /*  1330 */   176,  217,  159,  218,  217,  159,  132,  133,  134,  135,
+ /*  1340 */   136,  218,  217,  137,  179,   95,  179,   89,   90,  228,
+ /*  1350 */   129,  126,  128,  127,   96,   97,   98,  206,  231,  101,
+ /*  1360 */     5,   25,  231,  205,  207,   10,   11,   12,   13,   14,
+ /*  1370 */   204,  203,   17,   26,  162,  161,   13,    6,  180,  180,
+ /*  1380 */   153,  153,  151,  151,  151,  151,  167,   32,    4,   34,
+ /*  1390 */   132,  133,  134,  135,  136,    3,   22,  142,   43,   68,
+ /*  1400 */    15,   23,   16,  251,   23,  120,  251,  248,  131,  111,
+ /*  1410 */   123,   56,   16,   20,  125,    1,  123,  131,   63,   79,
+ /*  1420 */    79,   66,   67,  111,   36,   28,  122,    1,    5,   22,
+ /*  1430 */   107,  140,   26,   54,   54,   44,   61,  107,   20,   24,
+ /*  1440 */    19,  112,  105,   53,   22,   40,   22,   22,   53,   30,
+ /*  1450 */    23,   22,   22,   53,   23,   23,   23,   22,  116,   23,
+ /*  1460 */    22,  122,   23,   26,   23,   22,   11,  124,   28,  114,
+ /*  1470 */    36,   26,   26,   23,   23,   23,  122,   23,   36,   26,
+ /*  1480 */    36,   22,   24,   23,   22,    1,   23,   26,   22,   24,
+ /*  1490 */    23,   22,  122,   23,   23,   22,  141,   23,  122,  122,
+ /*  1500 */    15,
 };
-#define YY_SHIFT_USE_DFLT (-86)
-#define YY_SHIFT_COUNT (429)
-#define YY_SHIFT_MIN   (-85)
-#define YY_SHIFT_MAX   (1383)
+#define YY_SHIFT_USE_DFLT (-72)
+#define YY_SHIFT_COUNT (435)
+#define YY_SHIFT_MIN   (-71)
+#define YY_SHIFT_MAX   (1485)
 static const short yy_shift_ofst[] = {
- /*     0 */   992, 1057, 1355, 1156, 1204, 1204,    1,  262,  -19,  135,
- /*    10 */   135,  776, 1204, 1204, 1204, 1204,   69,   69,   53,  208,
- /*    20 */   283,  755,   58,  725,  648,  571,  494,  417,  340,  263,
- /*    30 */   212,  827,  827,  827,  827,  827,  827,  827,  827,  827,
- /*    40 */   827,  827,  827,  827,  827,  827,  878,  827,  929,  980,
- /*    50 */   980, 1070, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204,
+ /*     0 */     5, 1057, 1355, 1070, 1204, 1204, 1204,   90,   60,  -19,
+ /*    10 */    58,   58,  186, 1204, 1204, 1204, 1204, 1204, 1204, 1204,
+ /*    20 */    67,   67,  182,  336,   65,  250,  135,  263,  340,  417,
+ /*    30 */   494,  571,  622,  699,  776,  827,  827,  827,  827,  827,
+ /*    40 */   827,  827,  827,  827,  827,  827,  827,  827,  827,  827,
+ /*    50 */   878,  827,  929,  980,  980, 1156, 1204, 1204, 1204, 1204,
  /*    60 */  1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204,
  /*    70 */  1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204,
- /*    80 */  1258, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204,
- /*    90 */  1204, 1204, 1204, 1204,  -71,  -47,  -47,  -47,  -47,  -47,
- /*   100 */     0,   29,  -12,  283,  283,  139,   91,  392,  392,  894,
- /*   110 */   672,  726, 1383,  -86,  -86,  -86,   88,  318,  318,   99,
- /*   120 */   381,  -20,  283,  283,  283,  283,  283,  283,  283,  283,
- /*   130 */   283,  283,  283,  283,  283,  283,  283,  283,  283,  283,
- /*   140 */   283,  283,  283,  283,  624,  876,  726,  672, 1340, 1340,
- /*   150 */  1340, 1340, 1340, 1340,  -86,  -86,  -86,  305,  136,  136,
- /*   160 */   142,  167,  226,  154,  137,  152,  283,  283,  283,  283,
- /*   170 */   283,  283,  283,  283,  283,  283,  283,  283,  283,  283,
- /*   180 */   283,  283,  283,  336,  336,  336,  283,  283,  352,  283,
- /*   190 */   283,  283,  283,  283,  228,  283,  283,  283,  283,  283,
- /*   200 */   283,  283,  283,  283,  283,  501,  569,  596,  596,  596,
- /*   210 */   507,  497,  441,  391,  353,  156,  156,  857,  353,  857,
- /*   220 */   735,  813,  639,  715,  156,  332,  715,  715,  496,  419,
- /*   230 */   646, 1357, 1184, 1184, 1335, 1335, 1184, 1341, 1260, 1144,
- /*   240 */  1346, 1346, 1346, 1346, 1184, 1306, 1144, 1341, 1260, 1260,
- /*   250 */  1144, 1184, 1306, 1206, 1284, 1184, 1184, 1306, 1184, 1306,
- /*   260 */  1184, 1306, 1262, 1207, 1207, 1207, 1274, 1262, 1207, 1217,
- /*   270 */  1207, 1274, 1207, 1207, 1185, 1200, 1185, 1200, 1185, 1200,
- /*   280 */  1184, 1184, 1161, 1262, 1202, 1202, 1262, 1154, 1155, 1147,
- /*   290 */  1152, 1144, 1241, 1239, 1250, 1250, 1254, 1254, 1254, 1254,
- /*   300 */   -86,  -86,  -86,  -86,  -86,  -86, 1068,  304,  526,  249,
- /*   310 */   408,  -83,  434,  812,   27,  811,  807,  802,  751,  589,
- /*   320 */   651,  163,  131,  674,  366,  450,  299,  148,   23,  102,
- /*   330 */   229,  -21, 1245, 1244, 1222, 1099, 1228, 1172, 1223, 1215,
- /*   340 */  1213, 1115, 1106, 1123, 1110, 1209, 1105, 1212, 1226, 1098,
- /*   350 */  1089, 1140, 1139, 1104, 1189, 1178, 1094, 1211, 1205, 1187,
- /*   360 */  1101, 1071, 1153, 1175, 1146, 1138, 1151, 1091, 1164, 1165,
- /*   370 */  1163, 1069, 1072, 1148, 1112, 1134, 1127, 1129, 1126, 1092,
- /*   380 */  1114, 1118, 1088, 1090, 1093, 1087, 1084,  987, 1079, 1077,
- /*   390 */  1074, 1065,  924, 1021, 1014, 1004, 1006,  819,  739,  896,
- /*   400 */   855,  804,  739,  740,  736,  690,  654,  665,  618,  582,
- /*   410 */   568,  528,  554,  379,  532,  479,  455,  379,  432,  371,
- /*   420 */   341,   28,  338,  116,  -11,  -57,  -85,    7,   -8,    3,
+ /*    80 */  1204, 1204, 1204, 1204, 1258, 1204, 1204, 1204, 1204, 1204,
+ /*    90 */  1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204,  -71,  -47,
+ /*   100 */   -47,  -47,  -47,  -47,   -6,   88,  -66,   65,   65,  451,
+ /*   110 */   502,  112,  112,   33,  127,  278,  -30,  -72,  -72,  -72,
+ /*   120 */    11,  412,  412,  268,  608,  610,   65,   65,   65,   65,
+ /*   130 */    65,   65,   65,   65,   65,   65,   65,   65,   65,   65,
+ /*   140 */    65,   65,   65,   65,   65,  559,  138,  278,  127,   24,
+ /*   150 */    24,   24,   24,   24,   24,  -72,  -72,  -72,  228,  341,
+ /*   160 */   341,  207,  276,  300,  352,  354,  350,   65,   65,   65,
+ /*   170 */    65,   65,   65,   65,   65,   65,   65,   65,   65,   65,
+ /*   180 */    65,   65,   65,   65,  495,  495,  495,   65,   65,  499,
+ /*   190 */    65,   65,   65,  574,   65,   65,  517,   65,   65,   65,
+ /*   200 */    65,   65,   65,   65,   65,   65,   65,  566,  691,  288,
+ /*   210 */   288,  288,  701,  620, 1058,  675,  603,  964,  964,  967,
+ /*   220 */   603,  967,  722,  965,  936,  999,  964,  264,  999,  999,
+ /*   230 */   911,  921,  434, 1196, 1119, 1119, 1202, 1202, 1119, 1222,
+ /*   240 */  1184, 1126, 1244, 1244, 1244, 1244, 1119, 1251, 1126, 1222,
+ /*   250 */  1184, 1184, 1126, 1119, 1251, 1145, 1237, 1119, 1119, 1251,
+ /*   260 */  1275, 1119, 1251, 1119, 1251, 1275, 1203, 1203, 1203, 1264,
+ /*   270 */  1275, 1203, 1211, 1203, 1264, 1203, 1203, 1194, 1216, 1194,
+ /*   280 */  1216, 1194, 1216, 1194, 1216, 1119, 1119, 1206, 1275, 1250,
+ /*   290 */  1250, 1275, 1221, 1225, 1224, 1226, 1126, 1336, 1347, 1363,
+ /*   300 */  1363, 1371, 1371, 1371, 1371,  -72,  -72,  -72,  -72,  -72,
+ /*   310 */   -72,  477,  623,  742,  819,  624,  694,   74, 1023,  221,
+ /*   320 */  1055, 1065, 1077, 1087, 1080,  889, 1031,  939, 1093, 1122,
+ /*   330 */  1085, 1139,  961, 1024, 1172, 1103,  821, 1384, 1392, 1374,
+ /*   340 */  1255, 1385, 1331, 1386, 1378, 1381, 1285, 1277, 1298, 1287,
+ /*   350 */  1393, 1289, 1396, 1414, 1293, 1286, 1340, 1341, 1312, 1397,
+ /*   360 */  1388, 1304, 1426, 1423, 1407, 1323, 1291, 1379, 1406, 1380,
+ /*   370 */  1375, 1391, 1330, 1415, 1418, 1421, 1329, 1337, 1422, 1390,
+ /*   380 */  1424, 1425, 1427, 1429, 1395, 1419, 1430, 1400, 1405, 1431,
+ /*   390 */  1432, 1433, 1342, 1435, 1436, 1438, 1437, 1339, 1439, 1441,
+ /*   400 */  1440, 1434, 1443, 1343, 1445, 1442, 1446, 1444, 1445, 1450,
+ /*   410 */  1451, 1452, 1453, 1454, 1459, 1455, 1460, 1462, 1458, 1461,
+ /*   420 */  1463, 1466, 1465, 1461, 1467, 1469, 1470, 1471, 1473, 1354,
+ /*   430 */  1370, 1376, 1377, 1474, 1485, 1484,
 };
-#define YY_REDUCE_USE_DFLT (-110)
-#define YY_REDUCE_COUNT (305)
-#define YY_REDUCE_MIN   (-109)
-#define YY_REDUCE_MAX   (1323)
+#define YY_REDUCE_USE_DFLT (-176)
+#define YY_REDUCE_COUNT (310)
+#define YY_REDUCE_MIN   (-175)
+#define YY_REDUCE_MAX   (1234)
 static const short yy_reduce_ofst[] = {
- /*     0 */   238,  954,  213,  289,  310,  234,  144,  317, -109,  382,
- /*    10 */   377,  303,  461,  389,  378,  368,  302,  294,  253,  395,
- /*    20 */   293,  324,  403,  403,  403,  403,  403,  403,  403,  403,
- /*    30 */   403,  403,  403,  403,  403,  403,  403,  403,  403,  403,
- /*    40 */   403,  403,  403,  403,  403,  403,  403,  403,  403,  403,
- /*    50 */   403, 1022, 1012, 1005,  998,  963,  961,  959,  957,  950,
- /*    60 */   947,  930,  912,  873,  861,  823,  810,  771,  759,  720,
- /*    70 */   708,  670,  657,  619,  614,  612,  610,  608,  606,  604,
- /*    80 */   598,  595,  593,  580,  542,  540,  537,  535,  533,  531,
- /*    90 */   529,  527,  503,  386,  403,  403,  403,  403,  403,  403,
- /*   100 */   403,  403,  403,   95,  447,   82,  334,  504,  467,  403,
- /*   110 */   477,  464,  403,  403,  403,  403,  860,  747,  744,  785,
- /*   120 */   638,  638,  926,  891,  900,  899,  887,  844,  840,  835,
- /*   130 */   848,  830,  843,  829,  792,  839,  826,  737,  838,  795,
- /*   140 */   789,   47,  734,  530,  696,  777,  711,  677,  733,  730,
- /*   150 */   729,  728,  727,  627,  448,   64,  187, 1305, 1302, 1252,
- /*   160 */  1290, 1273, 1323, 1322, 1321, 1319, 1318, 1316, 1315, 1314,
- /*   170 */  1313, 1312, 1311, 1310, 1308, 1307, 1304, 1303, 1301, 1298,
- /*   180 */  1294, 1292, 1289, 1266, 1264, 1259, 1288, 1287, 1238, 1285,
- /*   190 */  1281, 1280, 1279, 1278, 1251, 1277, 1276, 1275, 1273, 1268,
- /*   200 */  1267, 1265, 1263, 1261, 1257, 1248, 1237, 1247, 1246, 1243,
- /*   210 */  1238, 1240, 1235, 1249, 1234, 1233, 1230, 1220, 1214, 1210,
- /*   220 */  1225, 1219, 1232, 1231, 1197, 1195, 1227, 1224, 1201, 1208,
- /*   230 */  1242, 1137, 1236, 1229, 1193, 1181, 1221, 1177, 1196, 1179,
- /*   240 */  1191, 1190, 1186, 1182, 1218, 1216, 1176, 1162, 1183, 1180,
- /*   250 */  1160, 1199, 1203, 1133, 1095, 1198, 1194, 1188, 1192, 1171,
- /*   260 */  1169, 1168, 1173, 1174, 1166, 1159, 1141, 1170, 1158, 1167,
- /*   270 */  1157, 1132, 1145, 1143, 1124, 1128, 1103, 1102, 1100, 1096,
- /*   280 */  1150, 1149, 1085, 1125, 1080, 1064, 1120, 1097, 1082, 1078,
- /*   290 */  1073, 1067, 1109, 1107, 1119, 1117, 1116, 1113, 1111, 1108,
- /*   300 */  1007, 1000, 1002, 1076, 1075, 1081,
+ /*     0 */  -143,  954,   86,   21,  -50,   23,   79,  134,  170, -175,
+ /*    10 */   229,  260, -121,  212,  219,  291,  -54,  349,  362,  156,
+ /*    20 */   309,  311,  334,   85,  224,  394,  314,  314,  314,  314,
+ /*    30 */   314,  314,  314,  314,  314,  314,  314,  314,  314,  314,
+ /*    40 */   314,  314,  314,  314,  314,  314,  314,  314,  314,  314,
+ /*    50 */   314,  314,  314,  314,  314,  374,  441,  443,  450,  452,
+ /*    60 */   515,  554,  567,  569,  572,  578,  580,  582,  584,  587,
+ /*    70 */   593,  631,  644,  646,  649,  655,  657,  659,  661,  664,
+ /*    80 */   708,  720,  759,  771,  810,  822,  861,  873,  912,  930,
+ /*    90 */   947,  950,  957,  959,  963,  966,  968,  998,  314,  314,
+ /*   100 */   314,  314,  314,  314,  314,  314,  314,  447,  -53,  166,
+ /*   110 */   438,  348,  363,  314,  473,  469,  314,  314,  314,  314,
+ /*   120 */   -15,   59,  101,  688,  220,  220,  525,  256,  729,  735,
+ /*   130 */   736,  740,  741,  744,  645,  448,  738,  458,  786,  503,
+ /*   140 */   780,  656,  721,  724,  792,  545,  568,  706,  683,  681,
+ /*   150 */   779,  784,  830,  831,  835,  678,  601, -104,   -2,   96,
+ /*   160 */   111,  218,  287,  308,  310,  312,  335,  411,  453,  461,
+ /*   170 */   573,  599,  617,  658,  665,  670,  732,  734,  775,  848,
+ /*   180 */   875,  892,  893,  898,  332,  420,  869,  931,  944,  886,
+ /*   190 */   983,  992, 1009,  958, 1017, 1028,  988, 1033, 1034, 1035,
+ /*   200 */   287, 1036, 1044, 1045, 1047, 1049, 1056,  915,  972,  997,
+ /*   210 */  1000, 1002,  886, 1011, 1015, 1061, 1013, 1001, 1003,  977,
+ /*   220 */  1018,  979, 1050, 1041, 1040, 1052, 1014, 1004, 1059, 1060,
+ /*   230 */  1032, 1038, 1084,  995, 1089, 1090, 1008, 1016, 1092, 1037,
+ /*   240 */  1068, 1062, 1069, 1072, 1073, 1074, 1105, 1112, 1071, 1048,
+ /*   250 */  1081, 1088, 1078, 1116, 1118, 1046, 1066, 1128, 1136, 1140,
+ /*   260 */  1120, 1147, 1146, 1148, 1150, 1130, 1135, 1137, 1138, 1132,
+ /*   270 */  1141, 1142, 1143, 1149, 1144, 1153, 1154, 1104, 1107, 1108,
+ /*   280 */  1114, 1115, 1117, 1123, 1125, 1173, 1176, 1121, 1165, 1127,
+ /*   290 */  1131, 1167, 1157, 1151, 1158, 1166, 1168, 1212, 1214, 1227,
+ /*   300 */  1228, 1231, 1232, 1233, 1234, 1152, 1155, 1159, 1198, 1199,
+ /*   310 */  1219,
 };
 static const YYACTIONTYPE yy_default[] = {
- /*     0 */   647,  964,  964,  964,  878,  878,  969,  964,  774,  802,
- /*    10 */   802,  938,  969,  969,  969,  876,  969,  969,  969,  964,
- /*    20 */   969,  778,  808,  969,  969,  969,  969,  969,  969,  969,
- /*    30 */   969,  937,  939,  816,  815,  918,  789,  813,  806,  810,
- /*    40 */   879,  872,  873,  871,  875,  880,  969,  809,  841,  856,
- /*    50 */   840,  969,  969,  969,  969,  969,  969,  969,  969,  969,
- /*    60 */   969,  969,  969,  969,  969,  969,  969,  969,  969,  969,
- /*    70 */   969,  969,  969,  969,  969,  969,  969,  969,  969,  969,
- /*    80 */   969,  969,  969,  969,  969,  969,  969,  969,  969,  969,
- /*    90 */   969,  969,  969,  969,  850,  855,  862,  854,  851,  843,
- /*   100 */   842,  844,  845,  969,  969,  673,  739,  969,  969,  846,
- /*   110 */   969,  685,  847,  859,  858,  857,  680,  969,  969,  969,
- /*   120 */   969,  969,  969,  969,  969,  969,  969,  969,  969,  969,
- /*   130 */   969,  969,  969,  969,  969,  969,  969,  969,  969,  969,
- /*   140 */   969,  969,  969,  969,  647,  964,  969,  969,  964,  964,
- /*   150 */   964,  964,  964,  964,  956,  778,  768,  969,  969,  969,
- /*   160 */   969,  969,  969,  969,  969,  969,  969,  944,  942,  969,
- /*   170 */   891,  969,  969,  969,  969,  969,  969,  969,  969,  969,
- /*   180 */   969,  969,  969,  969,  969,  969,  969,  969,  969,  969,
- /*   190 */   969,  969,  969,  969,  969,  969,  969,  969,  969,  969,
- /*   200 */   969,  969,  969,  969,  653,  969,  911,  774,  774,  774,
- /*   210 */   776,  754,  766,  655,  812,  791,  791,  923,  812,  923,
- /*   220 */   710,  733,  707,  802,  791,  874,  802,  802,  775,  766,
- /*   230 */   969,  949,  782,  782,  941,  941,  782,  821,  743,  812,
- /*   240 */   750,  750,  750,  750,  782,  670,  812,  821,  743,  743,
- /*   250 */   812,  782,  670,  917,  915,  782,  782,  670,  782,  670,
- /*   260 */   782,  670,  884,  741,  741,  741,  725,  884,  741,  710,
- /*   270 */   741,  725,  741,  741,  795,  790,  795,  790,  795,  790,
- /*   280 */   782,  782,  969,  884,  888,  888,  884,  807,  796,  805,
- /*   290 */   803,  812,  676,  728,  663,  663,  652,  652,  652,  652,
- /*   300 */   961,  961,  956,  712,  712,  695,  969,  969,  969,  969,
- /*   310 */   969,  969,  687,  969,  893,  969,  969,  969,  969,  969,
- /*   320 */   969,  969,  969,  969,  969,  969,  969,  969,  969,  969,
- /*   330 */   969,  828,  969,  648,  951,  969,  969,  948,  969,  969,
- /*   340 */   969,  969,  969,  969,  969,  969,  969,  969,  969,  969,
- /*   350 */   969,  969,  969,  969,  969,  969,  921,  969,  969,  969,
- /*   360 */   969,  969,  969,  914,  913,  969,  969,  969,  969,  969,
- /*   370 */   969,  969,  969,  969,  969,  969,  969,  969,  969,  969,
- /*   380 */   969,  969,  969,  969,  969,  969,  969,  757,  969,  969,
- /*   390 */   969,  761,  969,  969,  969,  969,  969,  969,  804,  969,
- /*   400 */   797,  969,  877,  969,  969,  969,  969,  969,  969,  969,
- /*   410 */   969,  969,  969,  966,  969,  969,  969,  965,  969,  969,
- /*   420 */   969,  969,  969,  830,  969,  829,  833,  969,  661,  969,
- /*   430 */   644,  649,  960,  963,  962,  959,  958,  957,  952,  950,
- /*   440 */   947,  946,  945,  943,  940,  936,  897,  895,  902,  901,
- /*   450 */   900,  899,  898,  896,  894,  892,  818,  817,  814,  811,
- /*   460 */   753,  935,  890,  752,  749,  748,  669,  953,  920,  929,
- /*   470 */   928,  927,  822,  926,  925,  924,  922,  919,  906,  820,
- /*   480 */   819,  744,  882,  881,  672,  910,  909,  908,  912,  916,
- /*   490 */   907,  784,  751,  671,  668,  675,  679,  731,  732,  740,
- /*   500 */   738,  737,  736,  735,  734,  730,  681,  686,  724,  709,
- /*   510 */   708,  717,  716,  722,  721,  720,  719,  718,  715,  714,
- /*   520 */   713,  706,  705,  711,  704,  727,  726,  723,  703,  747,
- /*   530 */   746,  745,  742,  702,  701,  700,  833,  699,  698,  838,
- /*   540 */   837,  866,  826,  755,  759,  758,  762,  763,  771,  770,
- /*   550 */   769,  780,  781,  793,  792,  824,  823,  794,  779,  773,
- /*   560 */   772,  788,  787,  786,  785,  777,  767,  799,  798,  868,
- /*   570 */   783,  867,  865,  934,  933,  932,  931,  930,  870,  967,
- /*   580 */   968,  887,  889,  886,  801,  800,  885,  869,  839,  836,
- /*   590 */   690,  691,  905,  904,  903,  693,  692,  689,  688,  863,
- /*   600 */   860,  852,  864,  861,  853,  849,  848,  834,  832,  831,
- /*   610 */   827,  835,  760,  756,  825,  765,  764,  697,  696,  694,
- /*   620 */   678,  677,  674,  667,  665,  664,  666,  662,  660,  659,
- /*   630 */   658,  657,  656,  684,  683,  682,  654,  651,  650,  646,
- /*   640 */   645,  643,
+ /*     0 */   982, 1300, 1300, 1300, 1214, 1214, 1214, 1305, 1300, 1109,
+ /*    10 */  1138, 1138, 1274, 1305, 1305, 1305, 1305, 1305, 1305, 1212,
+ /*    20 */  1305, 1305, 1305, 1300, 1305, 1113, 1144, 1305, 1305, 1305,
+ /*    30 */  1305, 1305, 1305, 1305, 1305, 1273, 1275, 1152, 1151, 1254,
+ /*    40 */  1125, 1149, 1142, 1146, 1215, 1208, 1209, 1207, 1211, 1216,
+ /*    50 */  1305, 1145, 1177, 1192, 1176, 1305, 1305, 1305, 1305, 1305,
+ /*    60 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
+ /*    70 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
+ /*    80 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
+ /*    90 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1186, 1191,
+ /*   100 */  1198, 1190, 1187, 1179, 1178, 1180, 1181, 1305, 1305, 1008,
+ /*   110 */  1074, 1305, 1305, 1182, 1305, 1020, 1183, 1195, 1194, 1193,
+ /*   120 */  1015, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
+ /*   130 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
+ /*   140 */  1305, 1305, 1305, 1305, 1305,  982, 1300, 1305, 1305, 1300,
+ /*   150 */  1300, 1300, 1300, 1300, 1300, 1292, 1113, 1103, 1305, 1305,
+ /*   160 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1280, 1278,
+ /*   170 */  1305, 1227, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
+ /*   180 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
+ /*   190 */  1305, 1305, 1305, 1109, 1305, 1305, 1305, 1305, 1305, 1305,
+ /*   200 */  1305, 1305, 1305, 1305, 1305, 1305,  988, 1305, 1247, 1109,
+ /*   210 */  1109, 1109, 1111, 1089, 1101,  990, 1148, 1127, 1127, 1259,
+ /*   220 */  1148, 1259, 1045, 1068, 1042, 1138, 1127, 1210, 1138, 1138,
+ /*   230 */  1110, 1101, 1305, 1285, 1118, 1118, 1277, 1277, 1118, 1157,
+ /*   240 */  1078, 1148, 1085, 1085, 1085, 1085, 1118, 1005, 1148, 1157,
+ /*   250 */  1078, 1078, 1148, 1118, 1005, 1253, 1251, 1118, 1118, 1005,
+ /*   260 */  1220, 1118, 1005, 1118, 1005, 1220, 1076, 1076, 1076, 1060,
+ /*   270 */  1220, 1076, 1045, 1076, 1060, 1076, 1076, 1131, 1126, 1131,
+ /*   280 */  1126, 1131, 1126, 1131, 1126, 1118, 1118, 1305, 1220, 1224,
+ /*   290 */  1224, 1220, 1143, 1132, 1141, 1139, 1148, 1011, 1063,  998,
+ /*   300 */   998,  987,  987,  987,  987, 1297, 1297, 1292, 1047, 1047,
+ /*   310 */  1030, 1305, 1305, 1305, 1305, 1305, 1305, 1022, 1305, 1229,
+ /*   320 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
+ /*   330 */  1305, 1305, 1305, 1305, 1305, 1305, 1164, 1305,  983, 1287,
+ /*   340 */  1305, 1305, 1284, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
+ /*   350 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
+ /*   360 */  1305, 1257, 1305, 1305, 1305, 1305, 1305, 1305, 1250, 1249,
+ /*   370 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
+ /*   380 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
+ /*   390 */  1305, 1305, 1092, 1305, 1305, 1305, 1096, 1305, 1305, 1305,
+ /*   400 */  1305, 1305, 1305, 1305, 1140, 1305, 1133, 1305, 1213, 1305,
+ /*   410 */  1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1302,
+ /*   420 */  1305, 1305, 1305, 1301, 1305, 1305, 1305, 1305, 1305, 1166,
+ /*   430 */  1305, 1165, 1169, 1305,  996, 1305,
 };
 
 /* The next table maps tokens into fallback tokens.  If a construct
@@ -125524,9 +126847,13 @@ static const YYCODETYPE yyFallback[] = {
 **   +  The semantic value stored at this level of the stack.  This is
 **      the information used by the action routines in the grammar.
 **      It is sometimes called the "minor" token.
+**
+** After the "shift" half of a SHIFTREDUCE action, the stateno field
+** actually contains the reduce action for the second half of the
+** SHIFTREDUCE.
 */
 struct yyStackEntry {
-  YYACTIONTYPE stateno;  /* The state-number */
+  YYACTIONTYPE stateno;  /* The state-number, or reduce action in SHIFTREDUCE */
   YYCODETYPE major;      /* The major token value.  This is the code
                          ** number for the token at this stack level */
   YYMINORTYPE minor;     /* The user-supplied minor token value.  This
@@ -125632,18 +126959,18 @@ static const char *const yyTokenName[] = {
   "column",        "columnid",      "type",          "carglist",    
   "typetoken",     "typename",      "signed",        "plus_num",    
   "minus_num",     "ccons",         "term",          "expr",        
-  "onconf",        "sortorder",     "autoinc",       "idxlist_opt", 
+  "onconf",        "sortorder",     "autoinc",       "eidlist_opt", 
   "refargs",       "defer_subclause",  "refarg",        "refact",      
   "init_deferred_pred_opt",  "conslist",      "tconscomma",    "tcons",       
-  "idxlist",       "defer_subclause_opt",  "orconf",        "resolvetype", 
-  "raisetype",     "ifexists",      "fullname",      "selectnowith",
-  "oneselect",     "with",          "multiselect_op",  "distinct",    
-  "selcollist",    "from",          "where_opt",     "groupby_opt", 
-  "having_opt",    "orderby_opt",   "limit_opt",     "values",      
-  "nexprlist",     "exprlist",      "sclp",          "as",          
-  "seltablist",    "stl_prefix",    "joinop",        "indexed_opt", 
-  "on_opt",        "using_opt",     "joinop2",       "idlist",      
-  "sortlist",      "setlist",       "insert_cmd",    "inscollist_opt",
+  "sortlist",      "eidlist",       "defer_subclause_opt",  "orconf",      
+  "resolvetype",   "raisetype",     "ifexists",      "fullname",    
+  "selectnowith",  "oneselect",     "with",          "multiselect_op",
+  "distinct",      "selcollist",    "from",          "where_opt",   
+  "groupby_opt",   "having_opt",    "orderby_opt",   "limit_opt",   
+  "values",        "nexprlist",     "exprlist",      "sclp",        
+  "as",            "seltablist",    "stl_prefix",    "joinop",      
+  "indexed_opt",   "on_opt",        "using_opt",     "joinop2",     
+  "idlist",        "setlist",       "insert_cmd",    "idlist_opt",  
   "likeop",        "between_op",    "in_op",         "case_operand",
   "case_exprlist",  "case_else",     "uniqueflag",    "collate",     
   "nmnum",         "trigger_decl",  "trigger_cmd_list",  "trigger_time",
@@ -125724,7 +127051,7 @@ static const char *const yyRuleName[] = {
  /*  62 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
  /*  63 */ "ccons ::= UNIQUE onconf",
  /*  64 */ "ccons ::= CHECK LP expr RP",
- /*  65 */ "ccons ::= REFERENCES nm idxlist_opt refargs",
+ /*  65 */ "ccons ::= REFERENCES nm eidlist_opt refargs",
  /*  66 */ "ccons ::= defer_subclause",
  /*  67 */ "ccons ::= COLLATE ID|STRING",
  /*  68 */ "autoinc ::=",
@@ -125752,10 +127079,10 @@ static const char *const yyRuleName[] = {
  /*  90 */ "tconscomma ::= COMMA",
  /*  91 */ "tconscomma ::=",
  /*  92 */ "tcons ::= CONSTRAINT nm",
- /*  93 */ "tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf",
- /*  94 */ "tcons ::= UNIQUE LP idxlist RP onconf",
+ /*  93 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf",
+ /*  94 */ "tcons ::= UNIQUE LP sortlist RP onconf",
  /*  95 */ "tcons ::= CHECK LP expr RP onconf",
- /*  96 */ "tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt",
+ /*  96 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt",
  /*  97 */ "defer_subclause_opt ::=",
  /*  98 */ "defer_subclause_opt ::= defer_subclause",
  /*  99 */ "onconf ::=",
@@ -125768,7 +127095,7 @@ static const char *const yyRuleName[] = {
  /* 106 */ "cmd ::= DROP TABLE ifexists fullname",
  /* 107 */ "ifexists ::= IF EXISTS",
  /* 108 */ "ifexists ::=",
- /* 109 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm AS select",
+ /* 109 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select",
  /* 110 */ "cmd ::= DROP VIEW ifexists fullname",
  /* 111 */ "cmd ::= select",
  /* 112 */ "select ::= with selectnowith",
@@ -125797,195 +127124,196 @@ static const char *const yyRuleName[] = {
  /* 135 */ "stl_prefix ::= seltablist joinop",
  /* 136 */ "stl_prefix ::=",
  /* 137 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt",
- /* 138 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt",
- /* 139 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt",
- /* 140 */ "dbnm ::=",
- /* 141 */ "dbnm ::= DOT nm",
- /* 142 */ "fullname ::= nm dbnm",
- /* 143 */ "joinop ::= COMMA|JOIN",
- /* 144 */ "joinop ::= JOIN_KW JOIN",
- /* 145 */ "joinop ::= JOIN_KW nm JOIN",
- /* 146 */ "joinop ::= JOIN_KW nm nm JOIN",
- /* 147 */ "on_opt ::= ON expr",
- /* 148 */ "on_opt ::=",
- /* 149 */ "indexed_opt ::=",
- /* 150 */ "indexed_opt ::= INDEXED BY nm",
- /* 151 */ "indexed_opt ::= NOT INDEXED",
- /* 152 */ "using_opt ::= USING LP idlist RP",
- /* 153 */ "using_opt ::=",
- /* 154 */ "orderby_opt ::=",
- /* 155 */ "orderby_opt ::= ORDER BY sortlist",
- /* 156 */ "sortlist ::= sortlist COMMA expr sortorder",
- /* 157 */ "sortlist ::= expr sortorder",
- /* 158 */ "sortorder ::= ASC",
- /* 159 */ "sortorder ::= DESC",
- /* 160 */ "sortorder ::=",
- /* 161 */ "groupby_opt ::=",
- /* 162 */ "groupby_opt ::= GROUP BY nexprlist",
- /* 163 */ "having_opt ::=",
- /* 164 */ "having_opt ::= HAVING expr",
- /* 165 */ "limit_opt ::=",
- /* 166 */ "limit_opt ::= LIMIT expr",
- /* 167 */ "limit_opt ::= LIMIT expr OFFSET expr",
- /* 168 */ "limit_opt ::= LIMIT expr COMMA expr",
- /* 169 */ "cmd ::= with DELETE FROM fullname indexed_opt where_opt",
- /* 170 */ "where_opt ::=",
- /* 171 */ "where_opt ::= WHERE expr",
- /* 172 */ "cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt",
- /* 173 */ "setlist ::= setlist COMMA nm EQ expr",
- /* 174 */ "setlist ::= nm EQ expr",
- /* 175 */ "cmd ::= with insert_cmd INTO fullname inscollist_opt select",
- /* 176 */ "cmd ::= with insert_cmd INTO fullname inscollist_opt DEFAULT VALUES",
- /* 177 */ "insert_cmd ::= INSERT orconf",
- /* 178 */ "insert_cmd ::= REPLACE",
- /* 179 */ "inscollist_opt ::=",
- /* 180 */ "inscollist_opt ::= LP idlist RP",
- /* 181 */ "idlist ::= idlist COMMA nm",
- /* 182 */ "idlist ::= nm",
- /* 183 */ "expr ::= term",
- /* 184 */ "expr ::= LP expr RP",
- /* 185 */ "term ::= NULL",
- /* 186 */ "expr ::= ID|INDEXED",
- /* 187 */ "expr ::= JOIN_KW",
- /* 188 */ "expr ::= nm DOT nm",
- /* 189 */ "expr ::= nm DOT nm DOT nm",
- /* 190 */ "term ::= INTEGER|FLOAT|BLOB",
- /* 191 */ "term ::= STRING",
- /* 192 */ "expr ::= VARIABLE",
- /* 193 */ "expr ::= expr COLLATE ID|STRING",
- /* 194 */ "expr ::= CAST LP expr AS typetoken RP",
- /* 195 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
- /* 196 */ "expr ::= ID|INDEXED LP STAR RP",
- /* 197 */ "term ::= CTIME_KW",
- /* 198 */ "expr ::= expr AND expr",
- /* 199 */ "expr ::= expr OR expr",
- /* 200 */ "expr ::= expr LT|GT|GE|LE expr",
- /* 201 */ "expr ::= expr EQ|NE expr",
- /* 202 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
- /* 203 */ "expr ::= expr PLUS|MINUS expr",
- /* 204 */ "expr ::= expr STAR|SLASH|REM expr",
- /* 205 */ "expr ::= expr CONCAT expr",
- /* 206 */ "likeop ::= LIKE_KW|MATCH",
- /* 207 */ "likeop ::= NOT LIKE_KW|MATCH",
- /* 208 */ "expr ::= expr likeop expr",
- /* 209 */ "expr ::= expr likeop expr ESCAPE expr",
- /* 210 */ "expr ::= expr ISNULL|NOTNULL",
- /* 211 */ "expr ::= expr NOT NULL",
- /* 212 */ "expr ::= expr IS expr",
- /* 213 */ "expr ::= expr IS NOT expr",
- /* 214 */ "expr ::= NOT expr",
- /* 215 */ "expr ::= BITNOT expr",
- /* 216 */ "expr ::= MINUS expr",
- /* 217 */ "expr ::= PLUS expr",
- /* 218 */ "between_op ::= BETWEEN",
- /* 219 */ "between_op ::= NOT BETWEEN",
- /* 220 */ "expr ::= expr between_op expr AND expr",
- /* 221 */ "in_op ::= IN",
- /* 222 */ "in_op ::= NOT IN",
- /* 223 */ "expr ::= expr in_op LP exprlist RP",
- /* 224 */ "expr ::= LP select RP",
- /* 225 */ "expr ::= expr in_op LP select RP",
- /* 226 */ "expr ::= expr in_op nm dbnm",
- /* 227 */ "expr ::= EXISTS LP select RP",
- /* 228 */ "expr ::= CASE case_operand case_exprlist case_else END",
- /* 229 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
- /* 230 */ "case_exprlist ::= WHEN expr THEN expr",
- /* 231 */ "case_else ::= ELSE expr",
- /* 232 */ "case_else ::=",
- /* 233 */ "case_operand ::= expr",
- /* 234 */ "case_operand ::=",
- /* 235 */ "exprlist ::= nexprlist",
- /* 236 */ "exprlist ::=",
- /* 237 */ "nexprlist ::= nexprlist COMMA expr",
- /* 238 */ "nexprlist ::= expr",
- /* 239 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP idxlist RP where_opt",
- /* 240 */ "uniqueflag ::= UNIQUE",
- /* 241 */ "uniqueflag ::=",
- /* 242 */ "idxlist_opt ::=",
- /* 243 */ "idxlist_opt ::= LP idxlist RP",
- /* 244 */ "idxlist ::= idxlist COMMA nm collate sortorder",
- /* 245 */ "idxlist ::= nm collate sortorder",
- /* 246 */ "collate ::=",
- /* 247 */ "collate ::= COLLATE ID|STRING",
- /* 248 */ "cmd ::= DROP INDEX ifexists fullname",
- /* 249 */ "cmd ::= VACUUM",
- /* 250 */ "cmd ::= VACUUM nm",
- /* 251 */ "cmd ::= PRAGMA nm dbnm",
- /* 252 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
- /* 253 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
- /* 254 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
- /* 255 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
- /* 256 */ "nmnum ::= plus_num",
- /* 257 */ "nmnum ::= nm",
- /* 258 */ "nmnum ::= ON",
- /* 259 */ "nmnum ::= DELETE",
- /* 260 */ "nmnum ::= DEFAULT",
- /* 261 */ "plus_num ::= PLUS INTEGER|FLOAT",
- /* 262 */ "plus_num ::= INTEGER|FLOAT",
- /* 263 */ "minus_num ::= MINUS INTEGER|FLOAT",
- /* 264 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
- /* 265 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
- /* 266 */ "trigger_time ::= BEFORE",
- /* 267 */ "trigger_time ::= AFTER",
- /* 268 */ "trigger_time ::= INSTEAD OF",
- /* 269 */ "trigger_time ::=",
- /* 270 */ "trigger_event ::= DELETE|INSERT",
- /* 271 */ "trigger_event ::= UPDATE",
- /* 272 */ "trigger_event ::= UPDATE OF idlist",
- /* 273 */ "foreach_clause ::=",
- /* 274 */ "foreach_clause ::= FOR EACH ROW",
- /* 275 */ "when_clause ::=",
- /* 276 */ "when_clause ::= WHEN expr",
- /* 277 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
- /* 278 */ "trigger_cmd_list ::= trigger_cmd SEMI",
- /* 279 */ "trnm ::= nm",
- /* 280 */ "trnm ::= nm DOT nm",
- /* 281 */ "tridxby ::=",
- /* 282 */ "tridxby ::= INDEXED BY nm",
- /* 283 */ "tridxby ::= NOT INDEXED",
- /* 284 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt",
- /* 285 */ "trigger_cmd ::= insert_cmd INTO trnm inscollist_opt select",
- /* 286 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt",
- /* 287 */ "trigger_cmd ::= select",
- /* 288 */ "expr ::= RAISE LP IGNORE RP",
- /* 289 */ "expr ::= RAISE LP raisetype COMMA nm RP",
- /* 290 */ "raisetype ::= ROLLBACK",
- /* 291 */ "raisetype ::= ABORT",
- /* 292 */ "raisetype ::= FAIL",
- /* 293 */ "cmd ::= DROP TRIGGER ifexists fullname",
- /* 294 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
- /* 295 */ "cmd ::= DETACH database_kw_opt expr",
- /* 296 */ "key_opt ::=",
- /* 297 */ "key_opt ::= KEY expr",
- /* 298 */ "database_kw_opt ::= DATABASE",
- /* 299 */ "database_kw_opt ::=",
- /* 300 */ "cmd ::= REINDEX",
- /* 301 */ "cmd ::= REINDEX nm dbnm",
- /* 302 */ "cmd ::= ANALYZE",
- /* 303 */ "cmd ::= ANALYZE nm dbnm",
- /* 304 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
- /* 305 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column",
- /* 306 */ "add_column_fullname ::= fullname",
- /* 307 */ "kwcolumn_opt ::=",
- /* 308 */ "kwcolumn_opt ::= COLUMNKW",
- /* 309 */ "cmd ::= create_vtab",
- /* 310 */ "cmd ::= create_vtab LP vtabarglist RP",
- /* 311 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
- /* 312 */ "vtabarglist ::= vtabarg",
- /* 313 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
- /* 314 */ "vtabarg ::=",
- /* 315 */ "vtabarg ::= vtabarg vtabargtoken",
- /* 316 */ "vtabargtoken ::= ANY",
- /* 317 */ "vtabargtoken ::= lp anylist RP",
- /* 318 */ "lp ::= LP",
- /* 319 */ "anylist ::=",
- /* 320 */ "anylist ::= anylist LP anylist RP",
- /* 321 */ "anylist ::= anylist ANY",
- /* 322 */ "with ::=",
- /* 323 */ "with ::= WITH wqlist",
- /* 324 */ "with ::= WITH RECURSIVE wqlist",
- /* 325 */ "wqlist ::= nm idxlist_opt AS LP select RP",
- /* 326 */ "wqlist ::= wqlist COMMA nm idxlist_opt AS LP select RP",
+ /* 138 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt",
+ /* 139 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt",
+ /* 140 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt",
+ /* 141 */ "dbnm ::=",
+ /* 142 */ "dbnm ::= DOT nm",
+ /* 143 */ "fullname ::= nm dbnm",
+ /* 144 */ "joinop ::= COMMA|JOIN",
+ /* 145 */ "joinop ::= JOIN_KW JOIN",
+ /* 146 */ "joinop ::= JOIN_KW nm JOIN",
+ /* 147 */ "joinop ::= JOIN_KW nm nm JOIN",
+ /* 148 */ "on_opt ::= ON expr",
+ /* 149 */ "on_opt ::=",
+ /* 150 */ "indexed_opt ::=",
+ /* 151 */ "indexed_opt ::= INDEXED BY nm",
+ /* 152 */ "indexed_opt ::= NOT INDEXED",
+ /* 153 */ "using_opt ::= USING LP idlist RP",
+ /* 154 */ "using_opt ::=",
+ /* 155 */ "orderby_opt ::=",
+ /* 156 */ "orderby_opt ::= ORDER BY sortlist",
+ /* 157 */ "sortlist ::= sortlist COMMA expr sortorder",
+ /* 158 */ "sortlist ::= expr sortorder",
+ /* 159 */ "sortorder ::= ASC",
+ /* 160 */ "sortorder ::= DESC",
+ /* 161 */ "sortorder ::=",
+ /* 162 */ "groupby_opt ::=",
+ /* 163 */ "groupby_opt ::= GROUP BY nexprlist",
+ /* 164 */ "having_opt ::=",
+ /* 165 */ "having_opt ::= HAVING expr",
+ /* 166 */ "limit_opt ::=",
+ /* 167 */ "limit_opt ::= LIMIT expr",
+ /* 168 */ "limit_opt ::= LIMIT expr OFFSET expr",
+ /* 169 */ "limit_opt ::= LIMIT expr COMMA expr",
+ /* 170 */ "cmd ::= with DELETE FROM fullname indexed_opt where_opt",
+ /* 171 */ "where_opt ::=",
+ /* 172 */ "where_opt ::= WHERE expr",
+ /* 173 */ "cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt",
+ /* 174 */ "setlist ::= setlist COMMA nm EQ expr",
+ /* 175 */ "setlist ::= nm EQ expr",
+ /* 176 */ "cmd ::= with insert_cmd INTO fullname idlist_opt select",
+ /* 177 */ "cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES",
+ /* 178 */ "insert_cmd ::= INSERT orconf",
+ /* 179 */ "insert_cmd ::= REPLACE",
+ /* 180 */ "idlist_opt ::=",
+ /* 181 */ "idlist_opt ::= LP idlist RP",
+ /* 182 */ "idlist ::= idlist COMMA nm",
+ /* 183 */ "idlist ::= nm",
+ /* 184 */ "expr ::= term",
+ /* 185 */ "expr ::= LP expr RP",
+ /* 186 */ "term ::= NULL",
+ /* 187 */ "expr ::= ID|INDEXED",
+ /* 188 */ "expr ::= JOIN_KW",
+ /* 189 */ "expr ::= nm DOT nm",
+ /* 190 */ "expr ::= nm DOT nm DOT nm",
+ /* 191 */ "term ::= INTEGER|FLOAT|BLOB",
+ /* 192 */ "term ::= STRING",
+ /* 193 */ "expr ::= VARIABLE",
+ /* 194 */ "expr ::= expr COLLATE ID|STRING",
+ /* 195 */ "expr ::= CAST LP expr AS typetoken RP",
+ /* 196 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
+ /* 197 */ "expr ::= ID|INDEXED LP STAR RP",
+ /* 198 */ "term ::= CTIME_KW",
+ /* 199 */ "expr ::= expr AND expr",
+ /* 200 */ "expr ::= expr OR expr",
+ /* 201 */ "expr ::= expr LT|GT|GE|LE expr",
+ /* 202 */ "expr ::= expr EQ|NE expr",
+ /* 203 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
+ /* 204 */ "expr ::= expr PLUS|MINUS expr",
+ /* 205 */ "expr ::= expr STAR|SLASH|REM expr",
+ /* 206 */ "expr ::= expr CONCAT expr",
+ /* 207 */ "likeop ::= LIKE_KW|MATCH",
+ /* 208 */ "likeop ::= NOT LIKE_KW|MATCH",
+ /* 209 */ "expr ::= expr likeop expr",
+ /* 210 */ "expr ::= expr likeop expr ESCAPE expr",
+ /* 211 */ "expr ::= expr ISNULL|NOTNULL",
+ /* 212 */ "expr ::= expr NOT NULL",
+ /* 213 */ "expr ::= expr IS expr",
+ /* 214 */ "expr ::= expr IS NOT expr",
+ /* 215 */ "expr ::= NOT expr",
+ /* 216 */ "expr ::= BITNOT expr",
+ /* 217 */ "expr ::= MINUS expr",
+ /* 218 */ "expr ::= PLUS expr",
+ /* 219 */ "between_op ::= BETWEEN",
+ /* 220 */ "between_op ::= NOT BETWEEN",
+ /* 221 */ "expr ::= expr between_op expr AND expr",
+ /* 222 */ "in_op ::= IN",
+ /* 223 */ "in_op ::= NOT IN",
+ /* 224 */ "expr ::= expr in_op LP exprlist RP",
+ /* 225 */ "expr ::= LP select RP",
+ /* 226 */ "expr ::= expr in_op LP select RP",
+ /* 227 */ "expr ::= expr in_op nm dbnm",
+ /* 228 */ "expr ::= EXISTS LP select RP",
+ /* 229 */ "expr ::= CASE case_operand case_exprlist case_else END",
+ /* 230 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
+ /* 231 */ "case_exprlist ::= WHEN expr THEN expr",
+ /* 232 */ "case_else ::= ELSE expr",
+ /* 233 */ "case_else ::=",
+ /* 234 */ "case_operand ::= expr",
+ /* 235 */ "case_operand ::=",
+ /* 236 */ "exprlist ::= nexprlist",
+ /* 237 */ "exprlist ::=",
+ /* 238 */ "nexprlist ::= nexprlist COMMA expr",
+ /* 239 */ "nexprlist ::= expr",
+ /* 240 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
+ /* 241 */ "uniqueflag ::= UNIQUE",
+ /* 242 */ "uniqueflag ::=",
+ /* 243 */ "eidlist_opt ::=",
+ /* 244 */ "eidlist_opt ::= LP eidlist RP",
+ /* 245 */ "eidlist ::= eidlist COMMA nm collate sortorder",
+ /* 246 */ "eidlist ::= nm collate sortorder",
+ /* 247 */ "collate ::=",
+ /* 248 */ "collate ::= COLLATE ID|STRING",
+ /* 249 */ "cmd ::= DROP INDEX ifexists fullname",
+ /* 250 */ "cmd ::= VACUUM",
+ /* 251 */ "cmd ::= VACUUM nm",
+ /* 252 */ "cmd ::= PRAGMA nm dbnm",
+ /* 253 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
+ /* 254 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
+ /* 255 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
+ /* 256 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
+ /* 257 */ "nmnum ::= plus_num",
+ /* 258 */ "nmnum ::= nm",
+ /* 259 */ "nmnum ::= ON",
+ /* 260 */ "nmnum ::= DELETE",
+ /* 261 */ "nmnum ::= DEFAULT",
+ /* 262 */ "plus_num ::= PLUS INTEGER|FLOAT",
+ /* 263 */ "plus_num ::= INTEGER|FLOAT",
+ /* 264 */ "minus_num ::= MINUS INTEGER|FLOAT",
+ /* 265 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
+ /* 266 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
+ /* 267 */ "trigger_time ::= BEFORE",
+ /* 268 */ "trigger_time ::= AFTER",
+ /* 269 */ "trigger_time ::= INSTEAD OF",
+ /* 270 */ "trigger_time ::=",
+ /* 271 */ "trigger_event ::= DELETE|INSERT",
+ /* 272 */ "trigger_event ::= UPDATE",
+ /* 273 */ "trigger_event ::= UPDATE OF idlist",
+ /* 274 */ "foreach_clause ::=",
+ /* 275 */ "foreach_clause ::= FOR EACH ROW",
+ /* 276 */ "when_clause ::=",
+ /* 277 */ "when_clause ::= WHEN expr",
+ /* 278 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
+ /* 279 */ "trigger_cmd_list ::= trigger_cmd SEMI",
+ /* 280 */ "trnm ::= nm",
+ /* 281 */ "trnm ::= nm DOT nm",
+ /* 282 */ "tridxby ::=",
+ /* 283 */ "tridxby ::= INDEXED BY nm",
+ /* 284 */ "tridxby ::= NOT INDEXED",
+ /* 285 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt",
+ /* 286 */ "trigger_cmd ::= insert_cmd INTO trnm idlist_opt select",
+ /* 287 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt",
+ /* 288 */ "trigger_cmd ::= select",
+ /* 289 */ "expr ::= RAISE LP IGNORE RP",
+ /* 290 */ "expr ::= RAISE LP raisetype COMMA nm RP",
+ /* 291 */ "raisetype ::= ROLLBACK",
+ /* 292 */ "raisetype ::= ABORT",
+ /* 293 */ "raisetype ::= FAIL",
+ /* 294 */ "cmd ::= DROP TRIGGER ifexists fullname",
+ /* 295 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
+ /* 296 */ "cmd ::= DETACH database_kw_opt expr",
+ /* 297 */ "key_opt ::=",
+ /* 298 */ "key_opt ::= KEY expr",
+ /* 299 */ "database_kw_opt ::= DATABASE",
+ /* 300 */ "database_kw_opt ::=",
+ /* 301 */ "cmd ::= REINDEX",
+ /* 302 */ "cmd ::= REINDEX nm dbnm",
+ /* 303 */ "cmd ::= ANALYZE",
+ /* 304 */ "cmd ::= ANALYZE nm dbnm",
+ /* 305 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
+ /* 306 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column",
+ /* 307 */ "add_column_fullname ::= fullname",
+ /* 308 */ "kwcolumn_opt ::=",
+ /* 309 */ "kwcolumn_opt ::= COLUMNKW",
+ /* 310 */ "cmd ::= create_vtab",
+ /* 311 */ "cmd ::= create_vtab LP vtabarglist RP",
+ /* 312 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
+ /* 313 */ "vtabarglist ::= vtabarg",
+ /* 314 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
+ /* 315 */ "vtabarg ::=",
+ /* 316 */ "vtabarg ::= vtabarg vtabargtoken",
+ /* 317 */ "vtabargtoken ::= ANY",
+ /* 318 */ "vtabargtoken ::= lp anylist RP",
+ /* 319 */ "lp ::= LP",
+ /* 320 */ "anylist ::=",
+ /* 321 */ "anylist ::= anylist LP anylist RP",
+ /* 322 */ "anylist ::= anylist ANY",
+ /* 323 */ "with ::=",
+ /* 324 */ "with ::= WITH wqlist",
+ /* 325 */ "with ::= WITH RECURSIVE wqlist",
+ /* 326 */ "wqlist ::= nm eidlist_opt AS LP select RP",
+ /* 327 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP",
 };
 #endif /* NDEBUG */
 
@@ -126065,9 +127393,9 @@ static void yy_destructor(
     ** inside the C code.
     */
     case 163: /* select */
-    case 195: /* selectnowith */
-    case 196: /* oneselect */
-    case 207: /* values */
+    case 196: /* selectnowith */
+    case 197: /* oneselect */
+    case 208: /* values */
 {
 sqlite3SelectDelete(pParse->db, (yypminor->yy3));
 }
@@ -126078,38 +127406,38 @@ sqlite3SelectDelete(pParse->db, (yypminor->yy3));
 sqlite3ExprDelete(pParse->db, (yypminor->yy346).pExpr);
 }
       break;
-    case 179: /* idxlist_opt */
-    case 188: /* idxlist */
-    case 200: /* selcollist */
-    case 203: /* groupby_opt */
-    case 205: /* orderby_opt */
-    case 208: /* nexprlist */
-    case 209: /* exprlist */
-    case 210: /* sclp */
-    case 220: /* sortlist */
+    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 221: /* setlist */
     case 228: /* case_exprlist */
 {
 sqlite3ExprListDelete(pParse->db, (yypminor->yy14));
 }
       break;
-    case 194: /* fullname */
-    case 201: /* from */
-    case 212: /* seltablist */
-    case 213: /* stl_prefix */
+    case 195: /* fullname */
+    case 202: /* from */
+    case 213: /* seltablist */
+    case 214: /* stl_prefix */
 {
 sqlite3SrcListDelete(pParse->db, (yypminor->yy65));
 }
       break;
-    case 197: /* with */
+    case 198: /* with */
     case 252: /* wqlist */
 {
 sqlite3WithDelete(pParse->db, (yypminor->yy59));
 }
       break;
-    case 202: /* where_opt */
-    case 204: /* having_opt */
-    case 216: /* on_opt */
+    case 203: /* where_opt */
+    case 205: /* having_opt */
+    case 217: /* on_opt */
     case 227: /* case_operand */
     case 229: /* case_else */
     case 238: /* when_clause */
@@ -126118,9 +127446,9 @@ sqlite3WithDelete(pParse->db, (yypminor->yy59));
 sqlite3ExprDelete(pParse->db, (yypminor->yy132));
 }
       break;
-    case 217: /* using_opt */
-    case 219: /* idlist */
-    case 223: /* inscollist_opt */
+    case 218: /* using_opt */
+    case 220: /* idlist */
+    case 223: /* idlist_opt */
 {
 sqlite3IdListDelete(pParse->db, (yypminor->yy408));
 }
@@ -126220,10 +127548,10 @@ static int yy_find_shift_action(
   int i;
   int stateno = pParser->yystack[pParser->yyidx].stateno;
  
-  if( stateno>YY_SHIFT_COUNT
-   || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){
-    return yy_default[stateno];
-  }
+  if( stateno>=YY_MIN_REDUCE ) return stateno;
+  assert( stateno <= YY_SHIFT_COUNT );
+  i = yy_shift_ofst[stateno];
+  if( i==YY_SHIFT_USE_DFLT ) return yy_default[stateno];
   assert( iLookAhead!=YYNOCODE );
   i += iLookAhead;
   if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
@@ -126326,7 +127654,29 @@ static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
 }
 
 /*
-** Perform a shift action.
+** Print tracing information for a SHIFT action
+*/
+#ifndef NDEBUG
+static void yyTraceShift(yyParser *yypParser, int yyNewState){
+  if( yyTraceFILE ){
+    int i;
+    if( yyNewState<YYNSTATE ){
+      fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
+      fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
+      for(i=1; i<=yypParser->yyidx; i++)
+        fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
+      fprintf(yyTraceFILE,"\n");
+    }else{
+      fprintf(yyTraceFILE,"%sShift *\n",yyTracePrompt);
+    }
+  }
+}
+#else
+# define yyTraceShift(X,Y)
+#endif
+
+/*
+** Perform a shift action.  Return the number of errors.
 */
 static void yy_shift(
   yyParser *yypParser,          /* The parser to be shifted */
@@ -126359,16 +127709,7 @@ static void yy_shift(
   yytos->stateno = (YYACTIONTYPE)yyNewState;
   yytos->major = (YYCODETYPE)yyMajor;
   yytos->minor = *yypMinor;
-#ifndef NDEBUG
-  if( yyTraceFILE && yypParser->yyidx>0 ){
-    int i;
-    fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
-    fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
-    for(i=1; i<=yypParser->yyidx; i++)
-      fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
-    fprintf(yyTraceFILE,"\n");
-  }
-#endif
+  yyTraceShift(yypParser, yyNewState);
 }
 
 /* The following table contains information about every rule that
@@ -126475,81 +127816,82 @@ static const struct {
   { 187, 5 },
   { 187, 5 },
   { 187, 10 },
-  { 189, 0 },
-  { 189, 1 },
+  { 190, 0 },
+  { 190, 1 },
   { 176, 0 },
   { 176, 3 },
-  { 190, 0 },
-  { 190, 2 },
-  { 191, 1 },
-  { 191, 1 },
-  { 191, 1 },
+  { 191, 0 },
+  { 191, 2 },
+  { 192, 1 },
+  { 192, 1 },
+  { 192, 1 },
   { 149, 4 },
-  { 193, 2 },
-  { 193, 0 },
-  { 149, 8 },
+  { 194, 2 },
+  { 194, 0 },
+  { 149, 9 },
   { 149, 4 },
   { 149, 1 },
   { 163, 2 },
-  { 195, 1 },
-  { 195, 3 },
-  { 198, 1 },
-  { 198, 2 },
-  { 198, 1 },
-  { 196, 9 },
   { 196, 1 },
-  { 207, 4 },
-  { 207, 5 },
+  { 196, 3 },
   { 199, 1 },
+  { 199, 2 },
   { 199, 1 },
-  { 199, 0 },
-  { 210, 2 },
-  { 210, 0 },
-  { 200, 3 },
-  { 200, 2 },
-  { 200, 4 },
+  { 197, 9 },
+  { 197, 1 },
+  { 208, 4 },
+  { 208, 5 },
+  { 200, 1 },
+  { 200, 1 },
+  { 200, 0 },
   { 211, 2 },
-  { 211, 1 },
   { 211, 0 },
-  { 201, 0 },
+  { 201, 3 },
   { 201, 2 },
-  { 213, 2 },
-  { 213, 0 },
-  { 212, 7 },
-  { 212, 7 },
-  { 212, 7 },
+  { 201, 4 },
+  { 212, 2 },
+  { 212, 1 },
+  { 212, 0 },
+  { 202, 0 },
+  { 202, 2 },
+  { 214, 2 },
+  { 214, 0 },
+  { 213, 7 },
+  { 213, 9 },
+  { 213, 7 },
+  { 213, 7 },
   { 159, 0 },
   { 159, 2 },
-  { 194, 2 },
-  { 214, 1 },
-  { 214, 2 },
-  { 214, 3 },
-  { 214, 4 },
-  { 216, 2 },
-  { 216, 0 },
-  { 215, 0 },
-  { 215, 3 },
+  { 195, 2 },
+  { 215, 1 },
   { 215, 2 },
-  { 217, 4 },
+  { 215, 3 },
+  { 215, 4 },
+  { 217, 2 },
   { 217, 0 },
-  { 205, 0 },
-  { 205, 3 },
-  { 220, 4 },
-  { 220, 2 },
+  { 216, 0 },
+  { 216, 3 },
+  { 216, 2 },
+  { 218, 4 },
+  { 218, 0 },
+  { 206, 0 },
+  { 206, 3 },
+  { 188, 4 },
+  { 188, 2 },
   { 177, 1 },
   { 177, 1 },
   { 177, 0 },
-  { 203, 0 },
-  { 203, 3 },
   { 204, 0 },
-  { 204, 2 },
-  { 206, 0 },
-  { 206, 2 },
-  { 206, 4 },
-  { 206, 4 },
+  { 204, 3 },
+  { 205, 0 },
+  { 205, 2 },
+  { 207, 0 },
+  { 207, 2 },
+  { 207, 4 },
+  { 207, 4 },
   { 149, 6 },
-  { 202, 0 },
-  { 202, 2 },
+  { 203, 0 },
+  { 203, 2 },
   { 149, 8 },
   { 221, 5 },
   { 221, 3 },
@@ -126559,8 +127901,8 @@ static const struct {
   { 222, 1 },
   { 223, 0 },
   { 223, 3 },
-  { 219, 3 },
-  { 219, 1 },
+  { 220, 3 },
+  { 220, 1 },
   { 175, 1 },
   { 175, 3 },
   { 174, 1 },
@@ -126613,17 +127955,17 @@ static const struct {
   { 229, 0 },
   { 227, 1 },
   { 227, 0 },
+  { 210, 1 },
+  { 210, 0 },
+  { 209, 3 },
   { 209, 1 },
-  { 209, 0 },
-  { 208, 3 },
-  { 208, 1 },
   { 149, 12 },
   { 230, 1 },
   { 230, 0 },
   { 179, 0 },
   { 179, 3 },
-  { 188, 5 },
-  { 188, 3 },
+  { 189, 5 },
+  { 189, 3 },
   { 231, 0 },
   { 231, 2 },
   { 149, 4 },
@@ -126668,9 +128010,9 @@ static const struct {
   { 239, 1 },
   { 175, 4 },
   { 175, 6 },
-  { 192, 1 },
-  { 192, 1 },
-  { 192, 1 },
+  { 193, 1 },
+  { 193, 1 },
+  { 193, 1 },
   { 149, 4 },
   { 149, 6 },
   { 149, 3 },
@@ -126700,9 +128042,9 @@ static const struct {
   { 251, 0 },
   { 251, 4 },
   { 251, 2 },
-  { 197, 0 },
-  { 197, 2 },
-  { 197, 3 },
+  { 198, 0 },
+  { 198, 2 },
+  { 198, 3 },
   { 252, 6 },
   { 252, 8 },
 };
@@ -126727,8 +128069,9 @@ static void yy_reduce(
 #ifndef NDEBUG
   if( yyTraceFILE && yyruleno>=0 
         && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
-    fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
-      yyRuleName[yyruleno]);
+    yysize = yyRuleInfo[yyruleno].nrhs;
+    fprintf(yyTraceFILE, "%sReduce [%s] -> state %d.\n", yyTracePrompt,
+      yyRuleName[yyruleno], yymsp[-yysize].stateno);
   }
 #endif /* NDEBUG */
 
@@ -126825,8 +128168,9 @@ static void yy_reduce(
       case 85: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ yytestcase(yyruleno==85);
       case 97: /* defer_subclause_opt ::= */ yytestcase(yyruleno==97);
       case 108: /* ifexists ::= */ yytestcase(yyruleno==108);
-      case 218: /* between_op ::= BETWEEN */ yytestcase(yyruleno==218);
-      case 221: /* in_op ::= IN */ yytestcase(yyruleno==221);
+      case 219: /* between_op ::= BETWEEN */ yytestcase(yyruleno==219);
+      case 222: /* in_op ::= IN */ yytestcase(yyruleno==222);
+      case 247: /* collate ::= */ yytestcase(yyruleno==247);
 {yygotominor.yy328 = 0;}
         break;
       case 29: /* ifnotexists ::= IF NOT EXISTS */
@@ -126834,8 +128178,9 @@ static void yy_reduce(
       case 69: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==69);
       case 84: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ yytestcase(yyruleno==84);
       case 107: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==107);
-      case 219: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==219);
-      case 222: /* in_op ::= NOT IN */ yytestcase(yyruleno==222);
+      case 220: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==220);
+      case 223: /* in_op ::= NOT IN */ yytestcase(yyruleno==223);
+      case 248: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==248);
 {yygotominor.yy328 = 1;}
         break;
       case 32: /* create_table_args ::= LP columnlist conslist_opt RP table_options */
@@ -126882,18 +128227,17 @@ static void yy_reduce(
       case 48: /* typename ::= ID|STRING */ yytestcase(yyruleno==48);
       case 130: /* as ::= AS nm */ yytestcase(yyruleno==130);
       case 131: /* as ::= ID|STRING */ yytestcase(yyruleno==131);
-      case 141: /* dbnm ::= DOT nm */ yytestcase(yyruleno==141);
-      case 150: /* indexed_opt ::= INDEXED BY nm */ yytestcase(yyruleno==150);
-      case 247: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==247);
-      case 256: /* nmnum ::= plus_num */ yytestcase(yyruleno==256);
-      case 257: /* nmnum ::= nm */ yytestcase(yyruleno==257);
-      case 258: /* nmnum ::= ON */ yytestcase(yyruleno==258);
-      case 259: /* nmnum ::= DELETE */ yytestcase(yyruleno==259);
-      case 260: /* nmnum ::= DEFAULT */ yytestcase(yyruleno==260);
-      case 261: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==261);
-      case 262: /* plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==262);
-      case 263: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==263);
-      case 279: /* trnm ::= nm */ yytestcase(yyruleno==279);
+      case 142: /* dbnm ::= DOT nm */ yytestcase(yyruleno==142);
+      case 151: /* indexed_opt ::= INDEXED BY nm */ yytestcase(yyruleno==151);
+      case 257: /* nmnum ::= plus_num */ yytestcase(yyruleno==257);
+      case 258: /* nmnum ::= nm */ yytestcase(yyruleno==258);
+      case 259: /* nmnum ::= ON */ yytestcase(yyruleno==259);
+      case 260: /* nmnum ::= DELETE */ yytestcase(yyruleno==260);
+      case 261: /* nmnum ::= DEFAULT */ yytestcase(yyruleno==261);
+      case 262: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==262);
+      case 263: /* plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==263);
+      case 264: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==264);
+      case 280: /* trnm ::= nm */ yytestcase(yyruleno==280);
 {yygotominor.yy0 = yymsp[0].minor.yy0;}
         break;
       case 44: /* type ::= typetoken */
@@ -126953,7 +128297,7 @@ static void yy_reduce(
       case 64: /* ccons ::= CHECK LP expr RP */
 {sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy346.pExpr);}
         break;
-      case 65: /* ccons ::= REFERENCES nm idxlist_opt refargs */
+      case 65: /* ccons ::= REFERENCES nm eidlist_opt refargs */
 {sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy14,yymsp[0].minor.yy328);}
         break;
       case 66: /* ccons ::= defer_subclause */
@@ -127008,16 +128352,16 @@ static void yy_reduce(
       case 90: /* tconscomma ::= COMMA */
 {pParse->constraintName.n = 0;}
         break;
-      case 93: /* tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf */
+      case 93: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
 {sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy14,yymsp[0].minor.yy328,yymsp[-2].minor.yy328,0);}
         break;
-      case 94: /* tcons ::= UNIQUE LP idxlist RP onconf */
+      case 94: /* tcons ::= UNIQUE LP sortlist RP onconf */
 {sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy14,yymsp[0].minor.yy328,0,0,0,0);}
         break;
       case 95: /* tcons ::= CHECK LP expr RP onconf */
 {sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy346.pExpr);}
         break;
-      case 96: /* tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt */
+      case 96: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
 {
     sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy14, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy14, yymsp[-1].minor.yy328);
     sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy328);
@@ -127043,9 +128387,9 @@ static void yy_reduce(
   sqlite3DropTable(pParse, yymsp[0].minor.yy65, 0, yymsp[-1].minor.yy328);
 }
         break;
-      case 109: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm AS select */
+      case 109: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
 {
-  sqlite3CreateView(pParse, &yymsp[-7].minor.yy0, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, yymsp[0].minor.yy3, yymsp[-6].minor.yy328, yymsp[-4].minor.yy328);
+  sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy14, yymsp[0].minor.yy3, yymsp[-7].minor.yy328, yymsp[-5].minor.yy328);
 }
         break;
       case 110: /* cmd ::= DROP VIEW ifexists fullname */
@@ -127162,14 +128506,14 @@ static void yy_reduce(
 {yygotominor.yy381 = 0;}
         break;
       case 125: /* sclp ::= selcollist COMMA */
-      case 243: /* idxlist_opt ::= LP idxlist RP */ yytestcase(yyruleno==243);
+      case 244: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==244);
 {yygotominor.yy14 = yymsp[-1].minor.yy14;}
         break;
       case 126: /* sclp ::= */
-      case 154: /* orderby_opt ::= */ yytestcase(yyruleno==154);
-      case 161: /* groupby_opt ::= */ yytestcase(yyruleno==161);
-      case 236: /* exprlist ::= */ yytestcase(yyruleno==236);
-      case 242: /* idxlist_opt ::= */ yytestcase(yyruleno==242);
+      case 155: /* orderby_opt ::= */ yytestcase(yyruleno==155);
+      case 162: /* groupby_opt ::= */ yytestcase(yyruleno==162);
+      case 237: /* exprlist ::= */ yytestcase(yyruleno==237);
+      case 243: /* eidlist_opt ::= */ yytestcase(yyruleno==243);
 {yygotominor.yy14 = 0;}
         break;
       case 127: /* selcollist ::= sclp expr as */
@@ -127208,7 +128552,7 @@ static void yy_reduce(
       case 135: /* stl_prefix ::= seltablist joinop */
 {
    yygotominor.yy65 = yymsp[-1].minor.yy65;
-   if( ALWAYS(yygotominor.yy65 && yygotominor.yy65->nSrc>0) ) yygotominor.yy65->a[yygotominor.yy65->nSrc-1].jointype = (u8)yymsp[0].minor.yy328;
+   if( ALWAYS(yygotominor.yy65 && yygotominor.yy65->nSrc>0) ) yygotominor.yy65->a[yygotominor.yy65->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy328;
 }
         break;
       case 136: /* stl_prefix ::= */
@@ -127220,12 +128564,18 @@ static void yy_reduce(
   sqlite3SrcListIndexedBy(pParse, yygotominor.yy65, &yymsp[-2].minor.yy0);
 }
         break;
-      case 138: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */
+      case 138: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
+{
+  yygotominor.yy65 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy65,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy132,yymsp[0].minor.yy408);
+  sqlite3SrcListFuncArgs(pParse, yygotominor.yy65, yymsp[-4].minor.yy14);
+}
+        break;
+      case 139: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */
 {
     yygotominor.yy65 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy65,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy3,yymsp[-1].minor.yy132,yymsp[0].minor.yy408);
   }
         break;
-      case 139: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
+      case 140: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
 {
     if( yymsp[-6].minor.yy65==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy132==0 && yymsp[0].minor.yy408==0 ){
       yygotominor.yy65 = yymsp[-4].minor.yy65;
@@ -127249,94 +128599,96 @@ static void yy_reduce(
     }
   }
         break;
-      case 140: /* dbnm ::= */
-      case 149: /* indexed_opt ::= */ yytestcase(yyruleno==149);
+      case 141: /* dbnm ::= */
+      case 150: /* indexed_opt ::= */ yytestcase(yyruleno==150);
 {yygotominor.yy0.z=0; yygotominor.yy0.n=0;}
         break;
-      case 142: /* fullname ::= nm dbnm */
+      case 143: /* fullname ::= nm dbnm */
 {yygotominor.yy65 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);}
         break;
-      case 143: /* joinop ::= COMMA|JOIN */
+      case 144: /* joinop ::= COMMA|JOIN */
 { yygotominor.yy328 = JT_INNER; }
         break;
-      case 144: /* joinop ::= JOIN_KW JOIN */
+      case 145: /* joinop ::= JOIN_KW JOIN */
 { yygotominor.yy328 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); }
         break;
-      case 145: /* joinop ::= JOIN_KW nm JOIN */
+      case 146: /* joinop ::= JOIN_KW nm JOIN */
 { yygotominor.yy328 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); }
         break;
-      case 146: /* joinop ::= JOIN_KW nm nm JOIN */
+      case 147: /* joinop ::= JOIN_KW nm nm JOIN */
 { yygotominor.yy328 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); }
         break;
-      case 147: /* on_opt ::= ON expr */
-      case 164: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==164);
-      case 171: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==171);
-      case 231: /* case_else ::= ELSE expr */ yytestcase(yyruleno==231);
-      case 233: /* case_operand ::= expr */ yytestcase(yyruleno==233);
+      case 148: /* on_opt ::= ON expr */
+      case 165: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==165);
+      case 172: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==172);
+      case 232: /* case_else ::= ELSE expr */ yytestcase(yyruleno==232);
+      case 234: /* case_operand ::= expr */ yytestcase(yyruleno==234);
 {yygotominor.yy132 = yymsp[0].minor.yy346.pExpr;}
         break;
-      case 148: /* on_opt ::= */
-      case 163: /* having_opt ::= */ yytestcase(yyruleno==163);
-      case 170: /* where_opt ::= */ yytestcase(yyruleno==170);
-      case 232: /* case_else ::= */ yytestcase(yyruleno==232);
-      case 234: /* case_operand ::= */ yytestcase(yyruleno==234);
+      case 149: /* on_opt ::= */
+      case 164: /* having_opt ::= */ yytestcase(yyruleno==164);
+      case 171: /* where_opt ::= */ yytestcase(yyruleno==171);
+      case 233: /* case_else ::= */ yytestcase(yyruleno==233);
+      case 235: /* case_operand ::= */ yytestcase(yyruleno==235);
 {yygotominor.yy132 = 0;}
         break;
-      case 151: /* indexed_opt ::= NOT INDEXED */
+      case 152: /* indexed_opt ::= NOT INDEXED */
 {yygotominor.yy0.z=0; yygotominor.yy0.n=1;}
         break;
-      case 152: /* using_opt ::= USING LP idlist RP */
-      case 180: /* inscollist_opt ::= LP idlist RP */ yytestcase(yyruleno==180);
+      case 153: /* using_opt ::= USING LP idlist RP */
+      case 181: /* idlist_opt ::= LP idlist RP */ yytestcase(yyruleno==181);
 {yygotominor.yy408 = yymsp[-1].minor.yy408;}
         break;
-      case 153: /* using_opt ::= */
-      case 179: /* inscollist_opt ::= */ yytestcase(yyruleno==179);
+      case 154: /* using_opt ::= */
+      case 180: /* idlist_opt ::= */ yytestcase(yyruleno==180);
 {yygotominor.yy408 = 0;}
         break;
-      case 155: /* orderby_opt ::= ORDER BY sortlist */
-      case 162: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==162);
-      case 235: /* exprlist ::= nexprlist */ yytestcase(yyruleno==235);
+      case 156: /* orderby_opt ::= ORDER BY sortlist */
+      case 163: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==163);
+      case 236: /* exprlist ::= nexprlist */ yytestcase(yyruleno==236);
 {yygotominor.yy14 = yymsp[0].minor.yy14;}
         break;
-      case 156: /* sortlist ::= sortlist COMMA expr sortorder */
+      case 157: /* sortlist ::= sortlist COMMA expr sortorder */
 {
   yygotominor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy14,yymsp[-1].minor.yy346.pExpr);
-  if( yygotominor.yy14 ) yygotominor.yy14->a[yygotominor.yy14->nExpr-1].sortOrder = (u8)yymsp[0].minor.yy328;
+  sqlite3ExprListSetSortOrder(yygotominor.yy14,yymsp[0].minor.yy328);
 }
         break;
-      case 157: /* sortlist ::= expr sortorder */
+      case 158: /* sortlist ::= expr sortorder */
 {
   yygotominor.yy14 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy346.pExpr);
-  if( yygotominor.yy14 && ALWAYS(yygotominor.yy14->a) ) yygotominor.yy14->a[0].sortOrder = (u8)yymsp[0].minor.yy328;
+  sqlite3ExprListSetSortOrder(yygotominor.yy14,yymsp[0].minor.yy328);
 }
         break;
-      case 158: /* sortorder ::= ASC */
-      case 160: /* sortorder ::= */ yytestcase(yyruleno==160);
+      case 159: /* sortorder ::= ASC */
 {yygotominor.yy328 = SQLITE_SO_ASC;}
         break;
-      case 159: /* sortorder ::= DESC */
+      case 160: /* sortorder ::= DESC */
 {yygotominor.yy328 = SQLITE_SO_DESC;}
         break;
-      case 165: /* limit_opt ::= */
+      case 161: /* sortorder ::= */
+{yygotominor.yy328 = SQLITE_SO_UNDEFINED;}
+        break;
+      case 166: /* limit_opt ::= */
 {yygotominor.yy476.pLimit = 0; yygotominor.yy476.pOffset = 0;}
         break;
-      case 166: /* limit_opt ::= LIMIT expr */
+      case 167: /* limit_opt ::= LIMIT expr */
 {yygotominor.yy476.pLimit = yymsp[0].minor.yy346.pExpr; yygotominor.yy476.pOffset = 0;}
         break;
-      case 167: /* limit_opt ::= LIMIT expr OFFSET expr */
+      case 168: /* limit_opt ::= LIMIT expr OFFSET expr */
 {yygotominor.yy476.pLimit = yymsp[-2].minor.yy346.pExpr; yygotominor.yy476.pOffset = yymsp[0].minor.yy346.pExpr;}
         break;
-      case 168: /* limit_opt ::= LIMIT expr COMMA expr */
+      case 169: /* limit_opt ::= LIMIT expr COMMA expr */
 {yygotominor.yy476.pOffset = yymsp[-2].minor.yy346.pExpr; yygotominor.yy476.pLimit = yymsp[0].minor.yy346.pExpr;}
         break;
-      case 169: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt */
+      case 170: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt */
 {
   sqlite3WithPush(pParse, yymsp[-5].minor.yy59, 1);
   sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy65, &yymsp[-1].minor.yy0);
   sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy65,yymsp[0].minor.yy132);
 }
         break;
-      case 172: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */
+      case 173: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */
 {
   sqlite3WithPush(pParse, yymsp[-7].minor.yy59, 1);
   sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy65, &yymsp[-3].minor.yy0);
@@ -127344,58 +128696,58 @@ static void yy_reduce(
   sqlite3Update(pParse,yymsp[-4].minor.yy65,yymsp[-1].minor.yy14,yymsp[0].minor.yy132,yymsp[-5].minor.yy186);
 }
         break;
-      case 173: /* setlist ::= setlist COMMA nm EQ expr */
+      case 174: /* setlist ::= setlist COMMA nm EQ expr */
 {
   yygotominor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy14, yymsp[0].minor.yy346.pExpr);
   sqlite3ExprListSetName(pParse, yygotominor.yy14, &yymsp[-2].minor.yy0, 1);
 }
         break;
-      case 174: /* setlist ::= nm EQ expr */
+      case 175: /* setlist ::= nm EQ expr */
 {
   yygotominor.yy14 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy346.pExpr);
   sqlite3ExprListSetName(pParse, yygotominor.yy14, &yymsp[-2].minor.yy0, 1);
 }
         break;
-      case 175: /* cmd ::= with insert_cmd INTO fullname inscollist_opt select */
+      case 176: /* cmd ::= with insert_cmd INTO fullname idlist_opt select */
 {
   sqlite3WithPush(pParse, yymsp[-5].minor.yy59, 1);
   sqlite3Insert(pParse, yymsp[-2].minor.yy65, yymsp[0].minor.yy3, yymsp[-1].minor.yy408, yymsp[-4].minor.yy186);
 }
         break;
-      case 176: /* cmd ::= with insert_cmd INTO fullname inscollist_opt DEFAULT VALUES */
+      case 177: /* cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */
 {
   sqlite3WithPush(pParse, yymsp[-6].minor.yy59, 1);
   sqlite3Insert(pParse, yymsp[-3].minor.yy65, 0, yymsp[-2].minor.yy408, yymsp[-5].minor.yy186);
 }
         break;
-      case 177: /* insert_cmd ::= INSERT orconf */
+      case 178: /* insert_cmd ::= INSERT orconf */
 {yygotominor.yy186 = yymsp[0].minor.yy186;}
         break;
-      case 178: /* insert_cmd ::= REPLACE */
+      case 179: /* insert_cmd ::= REPLACE */
 {yygotominor.yy186 = OE_Replace;}
         break;
-      case 181: /* idlist ::= idlist COMMA nm */
+      case 182: /* idlist ::= idlist COMMA nm */
 {yygotominor.yy408 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy408,&yymsp[0].minor.yy0);}
         break;
-      case 182: /* idlist ::= nm */
+      case 183: /* idlist ::= nm */
 {yygotominor.yy408 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0);}
         break;
-      case 183: /* expr ::= term */
+      case 184: /* expr ::= term */
 {yygotominor.yy346 = yymsp[0].minor.yy346;}
         break;
-      case 184: /* expr ::= LP expr RP */
+      case 185: /* expr ::= LP expr RP */
 {yygotominor.yy346.pExpr = yymsp[-1].minor.yy346.pExpr; spanSet(&yygotominor.yy346,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);}
         break;
-      case 185: /* term ::= NULL */
-      case 190: /* term ::= INTEGER|FLOAT|BLOB */ yytestcase(yyruleno==190);
-      case 191: /* term ::= STRING */ yytestcase(yyruleno==191);
+      case 186: /* term ::= NULL */
+      case 191: /* term ::= INTEGER|FLOAT|BLOB */ yytestcase(yyruleno==191);
+      case 192: /* term ::= STRING */ yytestcase(yyruleno==192);
 {spanExpr(&yygotominor.yy346, pParse, yymsp[0].major, &yymsp[0].minor.yy0);}
         break;
-      case 186: /* expr ::= ID|INDEXED */
-      case 187: /* expr ::= JOIN_KW */ yytestcase(yyruleno==187);
+      case 187: /* expr ::= ID|INDEXED */
+      case 188: /* expr ::= JOIN_KW */ yytestcase(yyruleno==188);
 {spanExpr(&yygotominor.yy346, pParse, TK_ID, &yymsp[0].minor.yy0);}
         break;
-      case 188: /* expr ::= nm DOT nm */
+      case 189: /* expr ::= nm DOT nm */
 {
   Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0);
   Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy0);
@@ -127403,7 +128755,7 @@ static void yy_reduce(
   spanSet(&yygotominor.yy346,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
 }
         break;
-      case 189: /* expr ::= nm DOT nm DOT nm */
+      case 190: /* expr ::= nm DOT nm DOT nm */
 {
   Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-4].minor.yy0);
   Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0);
@@ -127413,7 +128765,7 @@ static void yy_reduce(
   spanSet(&yygotominor.yy346,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
 }
         break;
-      case 192: /* expr ::= VARIABLE */
+      case 193: /* expr ::= VARIABLE */
 {
   if( yymsp[0].minor.yy0.n>=2 && yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1]) ){
     /* When doing a nested parse, one can include terms in an expression
@@ -127433,20 +128785,20 @@ static void yy_reduce(
   spanSet(&yygotominor.yy346, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
 }
         break;
-      case 193: /* expr ::= expr COLLATE ID|STRING */
+      case 194: /* expr ::= expr COLLATE ID|STRING */
 {
   yygotominor.yy346.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy346.pExpr, &yymsp[0].minor.yy0, 1);
   yygotominor.yy346.zStart = yymsp[-2].minor.yy346.zStart;
   yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
 }
         break;
-      case 194: /* expr ::= CAST LP expr AS typetoken RP */
+      case 195: /* expr ::= CAST LP expr AS typetoken RP */
 {
   yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_CAST, yymsp[-3].minor.yy346.pExpr, 0, &yymsp[-1].minor.yy0);
   spanSet(&yygotominor.yy346,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0);
 }
         break;
-      case 195: /* expr ::= ID|INDEXED LP distinct exprlist RP */
+      case 196: /* expr ::= ID|INDEXED LP distinct exprlist RP */
 {
   if( yymsp[-1].minor.yy14 && yymsp[-1].minor.yy14->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
     sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0);
@@ -127458,35 +128810,35 @@ static void yy_reduce(
   }
 }
         break;
-      case 196: /* expr ::= ID|INDEXED LP STAR RP */
+      case 197: /* expr ::= ID|INDEXED LP STAR RP */
 {
   yygotominor.yy346.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0);
   spanSet(&yygotominor.yy346,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
 }
         break;
-      case 197: /* term ::= CTIME_KW */
+      case 198: /* term ::= CTIME_KW */
 {
   yygotominor.yy346.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0);
   spanSet(&yygotominor.yy346, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
 }
         break;
-      case 198: /* expr ::= expr AND expr */
-      case 199: /* expr ::= expr OR expr */ yytestcase(yyruleno==199);
-      case 200: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==200);
-      case 201: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==201);
-      case 202: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==202);
-      case 203: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==203);
-      case 204: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==204);
-      case 205: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==205);
+      case 199: /* expr ::= expr AND expr */
+      case 200: /* expr ::= expr OR expr */ yytestcase(yyruleno==200);
+      case 201: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==201);
+      case 202: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==202);
+      case 203: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==203);
+      case 204: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==204);
+      case 205: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==205);
+      case 206: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==206);
 {spanBinaryExpr(&yygotominor.yy346,pParse,yymsp[-1].major,&yymsp[-2].minor.yy346,&yymsp[0].minor.yy346);}
         break;
-      case 206: /* likeop ::= LIKE_KW|MATCH */
+      case 207: /* likeop ::= LIKE_KW|MATCH */
 {yygotominor.yy96.eOperator = yymsp[0].minor.yy0; yygotominor.yy96.bNot = 0;}
         break;
-      case 207: /* likeop ::= NOT LIKE_KW|MATCH */
+      case 208: /* likeop ::= NOT LIKE_KW|MATCH */
 {yygotominor.yy96.eOperator = yymsp[0].minor.yy0; yygotominor.yy96.bNot = 1;}
         break;
-      case 208: /* expr ::= expr likeop expr */
+      case 209: /* expr ::= expr likeop expr */
 {
   ExprList *pList;
   pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy346.pExpr);
@@ -127498,7 +128850,7 @@ static void yy_reduce(
   if( yygotominor.yy346.pExpr ) yygotominor.yy346.pExpr->flags |= EP_InfixFunc;
 }
         break;
-      case 209: /* expr ::= expr likeop expr ESCAPE expr */
+      case 210: /* expr ::= expr likeop expr ESCAPE expr */
 {
   ExprList *pList;
   pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy346.pExpr);
@@ -127511,35 +128863,35 @@ static void yy_reduce(
   if( yygotominor.yy346.pExpr ) yygotominor.yy346.pExpr->flags |= EP_InfixFunc;
 }
         break;
-      case 210: /* expr ::= expr ISNULL|NOTNULL */
+      case 211: /* expr ::= expr ISNULL|NOTNULL */
 {spanUnaryPostfix(&yygotominor.yy346,pParse,yymsp[0].major,&yymsp[-1].minor.yy346,&yymsp[0].minor.yy0);}
         break;
-      case 211: /* expr ::= expr NOT NULL */
+      case 212: /* expr ::= expr NOT NULL */
 {spanUnaryPostfix(&yygotominor.yy346,pParse,TK_NOTNULL,&yymsp[-2].minor.yy346,&yymsp[0].minor.yy0);}
         break;
-      case 212: /* expr ::= expr IS expr */
+      case 213: /* expr ::= expr IS expr */
 {
   spanBinaryExpr(&yygotominor.yy346,pParse,TK_IS,&yymsp[-2].minor.yy346,&yymsp[0].minor.yy346);
   binaryToUnaryIfNull(pParse, yymsp[0].minor.yy346.pExpr, yygotominor.yy346.pExpr, TK_ISNULL);
 }
         break;
-      case 213: /* expr ::= expr IS NOT expr */
+      case 214: /* expr ::= expr IS NOT expr */
 {
   spanBinaryExpr(&yygotominor.yy346,pParse,TK_ISNOT,&yymsp[-3].minor.yy346,&yymsp[0].minor.yy346);
   binaryToUnaryIfNull(pParse, yymsp[0].minor.yy346.pExpr, yygotominor.yy346.pExpr, TK_NOTNULL);
 }
         break;
-      case 214: /* expr ::= NOT expr */
-      case 215: /* expr ::= BITNOT expr */ yytestcase(yyruleno==215);
+      case 215: /* expr ::= NOT expr */
+      case 216: /* expr ::= BITNOT expr */ yytestcase(yyruleno==216);
 {spanUnaryPrefix(&yygotominor.yy346,pParse,yymsp[-1].major,&yymsp[0].minor.yy346,&yymsp[-1].minor.yy0);}
         break;
-      case 216: /* expr ::= MINUS expr */
+      case 217: /* expr ::= MINUS expr */
 {spanUnaryPrefix(&yygotominor.yy346,pParse,TK_UMINUS,&yymsp[0].minor.yy346,&yymsp[-1].minor.yy0);}
         break;
-      case 217: /* expr ::= PLUS expr */
+      case 218: /* expr ::= PLUS expr */
 {spanUnaryPrefix(&yygotominor.yy346,pParse,TK_UPLUS,&yymsp[0].minor.yy346,&yymsp[-1].minor.yy0);}
         break;
-      case 220: /* expr ::= expr between_op expr AND expr */
+      case 221: /* expr ::= expr between_op expr AND expr */
 {
   ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy346.pExpr);
   pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy346.pExpr);
@@ -127554,7 +128906,7 @@ static void yy_reduce(
   yygotominor.yy346.zEnd = yymsp[0].minor.yy346.zEnd;
 }
         break;
-      case 223: /* expr ::= expr in_op LP exprlist RP */
+      case 224: /* expr ::= expr in_op LP exprlist RP */
 {
     if( yymsp[-1].minor.yy14==0 ){
       /* Expressions of the form
@@ -127608,7 +128960,7 @@ static void yy_reduce(
     yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
   }
         break;
-      case 224: /* expr ::= LP select RP */
+      case 225: /* expr ::= LP select RP */
 {
     yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
     if( yygotominor.yy346.pExpr ){
@@ -127622,7 +128974,7 @@ static void yy_reduce(
     yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
   }
         break;
-      case 225: /* expr ::= expr in_op LP select RP */
+      case 226: /* expr ::= expr in_op LP select RP */
 {
     yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy346.pExpr, 0, 0);
     if( yygotominor.yy346.pExpr ){
@@ -127637,7 +128989,7 @@ static void yy_reduce(
     yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
   }
         break;
-      case 226: /* expr ::= expr in_op nm dbnm */
+      case 227: /* expr ::= expr in_op nm dbnm */
 {
     SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);
     yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-3].minor.yy346.pExpr, 0, 0);
@@ -127653,7 +129005,7 @@ static void yy_reduce(
     yygotominor.yy346.zEnd = yymsp[0].minor.yy0.z ? &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] : &yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n];
   }
         break;
-      case 227: /* expr ::= EXISTS LP select RP */
+      case 228: /* expr ::= EXISTS LP select RP */
 {
     Expr *p = yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
     if( p ){
@@ -127667,7 +129019,7 @@ static void yy_reduce(
     yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
   }
         break;
-      case 228: /* expr ::= CASE case_operand case_exprlist case_else END */
+      case 229: /* expr ::= CASE case_operand case_exprlist case_else END */
 {
   yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy132, 0, 0);
   if( yygotominor.yy346.pExpr ){
@@ -127681,82 +129033,71 @@ static void yy_reduce(
   yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
 }
         break;
-      case 229: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
+      case 230: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
 {
   yygotominor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, yymsp[-2].minor.yy346.pExpr);
   yygotominor.yy14 = sqlite3ExprListAppend(pParse,yygotominor.yy14, yymsp[0].minor.yy346.pExpr);
 }
         break;
-      case 230: /* case_exprlist ::= WHEN expr THEN expr */
+      case 231: /* case_exprlist ::= WHEN expr THEN expr */
 {
   yygotominor.yy14 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy346.pExpr);
   yygotominor.yy14 = sqlite3ExprListAppend(pParse,yygotominor.yy14, yymsp[0].minor.yy346.pExpr);
 }
         break;
-      case 237: /* nexprlist ::= nexprlist COMMA expr */
+      case 238: /* nexprlist ::= nexprlist COMMA expr */
 {yygotominor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[0].minor.yy346.pExpr);}
         break;
-      case 238: /* nexprlist ::= expr */
+      case 239: /* nexprlist ::= expr */
 {yygotominor.yy14 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy346.pExpr);}
         break;
-      case 239: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP idxlist RP where_opt */
+      case 240: /* 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.yy14, yymsp[-10].minor.yy328,
                       &yymsp[-11].minor.yy0, yymsp[0].minor.yy132, SQLITE_SO_ASC, yymsp[-8].minor.yy328);
 }
         break;
-      case 240: /* uniqueflag ::= UNIQUE */
-      case 291: /* raisetype ::= ABORT */ yytestcase(yyruleno==291);
+      case 241: /* uniqueflag ::= UNIQUE */
+      case 292: /* raisetype ::= ABORT */ yytestcase(yyruleno==292);
 {yygotominor.yy328 = OE_Abort;}
         break;
-      case 241: /* uniqueflag ::= */
+      case 242: /* uniqueflag ::= */
 {yygotominor.yy328 = OE_None;}
         break;
-      case 244: /* idxlist ::= idxlist COMMA nm collate sortorder */
+      case 245: /* eidlist ::= eidlist COMMA nm collate sortorder */
 {
-  Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &yymsp[-1].minor.yy0, 1);
-  yygotominor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, p);
-  sqlite3ExprListSetName(pParse,yygotominor.yy14,&yymsp[-2].minor.yy0,1);
-  sqlite3ExprListCheckLength(pParse, yygotominor.yy14, "index");
-  if( yygotominor.yy14 ) yygotominor.yy14->a[yygotominor.yy14->nExpr-1].sortOrder = (u8)yymsp[0].minor.yy328;
+  yygotominor.yy14 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy14, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy328, yymsp[0].minor.yy328);
 }
         break;
-      case 245: /* idxlist ::= nm collate sortorder */
+      case 246: /* eidlist ::= nm collate sortorder */
 {
-  Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &yymsp[-1].minor.yy0, 1);
-  yygotominor.yy14 = sqlite3ExprListAppend(pParse,0, p);
-  sqlite3ExprListSetName(pParse, yygotominor.yy14, &yymsp[-2].minor.yy0, 1);
-  sqlite3ExprListCheckLength(pParse, yygotominor.yy14, "index");
-  if( yygotominor.yy14 ) yygotominor.yy14->a[yygotominor.yy14->nExpr-1].sortOrder = (u8)yymsp[0].minor.yy328;
+  yygotominor.yy14 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy328, yymsp[0].minor.yy328);
 }
         break;
-      case 246: /* collate ::= */
-{yygotominor.yy0.z = 0; yygotominor.yy0.n = 0;}
-        break;
-      case 248: /* cmd ::= DROP INDEX ifexists fullname */
+      case 249: /* cmd ::= DROP INDEX ifexists fullname */
 {sqlite3DropIndex(pParse, yymsp[0].minor.yy65, yymsp[-1].minor.yy328);}
         break;
-      case 249: /* cmd ::= VACUUM */
-      case 250: /* cmd ::= VACUUM nm */ yytestcase(yyruleno==250);
+      case 250: /* cmd ::= VACUUM */
+      case 251: /* cmd ::= VACUUM nm */ yytestcase(yyruleno==251);
 {sqlite3Vacuum(pParse);}
         break;
-      case 251: /* cmd ::= PRAGMA nm dbnm */
+      case 252: /* cmd ::= PRAGMA nm dbnm */
 {sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);}
         break;
-      case 252: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
+      case 253: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
 {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);}
         break;
-      case 253: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
+      case 254: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
 {sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);}
         break;
-      case 254: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
+      case 255: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
 {sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);}
         break;
-      case 255: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
+      case 256: /* 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 264: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
+      case 265: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
 {
   Token all;
   all.z = yymsp[-3].minor.yy0.z;
@@ -127764,38 +129105,38 @@ static void yy_reduce(
   sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy473, &all);
 }
         break;
-      case 265: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+      case 266: /* 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.yy328, yymsp[-4].minor.yy378.a, yymsp[-4].minor.yy378.b, yymsp[-2].minor.yy65, yymsp[0].minor.yy132, yymsp[-10].minor.yy328, yymsp[-8].minor.yy328);
   yygotominor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0);
 }
         break;
-      case 266: /* trigger_time ::= BEFORE */
-      case 269: /* trigger_time ::= */ yytestcase(yyruleno==269);
+      case 267: /* trigger_time ::= BEFORE */
+      case 270: /* trigger_time ::= */ yytestcase(yyruleno==270);
 { yygotominor.yy328 = TK_BEFORE; }
         break;
-      case 267: /* trigger_time ::= AFTER */
+      case 268: /* trigger_time ::= AFTER */
 { yygotominor.yy328 = TK_AFTER;  }
         break;
-      case 268: /* trigger_time ::= INSTEAD OF */
+      case 269: /* trigger_time ::= INSTEAD OF */
 { yygotominor.yy328 = TK_INSTEAD;}
         break;
-      case 270: /* trigger_event ::= DELETE|INSERT */
-      case 271: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==271);
+      case 271: /* trigger_event ::= DELETE|INSERT */
+      case 272: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==272);
 {yygotominor.yy378.a = yymsp[0].major; yygotominor.yy378.b = 0;}
         break;
-      case 272: /* trigger_event ::= UPDATE OF idlist */
+      case 273: /* trigger_event ::= UPDATE OF idlist */
 {yygotominor.yy378.a = TK_UPDATE; yygotominor.yy378.b = yymsp[0].minor.yy408;}
         break;
-      case 275: /* when_clause ::= */
-      case 296: /* key_opt ::= */ yytestcase(yyruleno==296);
+      case 276: /* when_clause ::= */
+      case 297: /* key_opt ::= */ yytestcase(yyruleno==297);
 { yygotominor.yy132 = 0; }
         break;
-      case 276: /* when_clause ::= WHEN expr */
-      case 297: /* key_opt ::= KEY expr */ yytestcase(yyruleno==297);
+      case 277: /* when_clause ::= WHEN expr */
+      case 298: /* key_opt ::= KEY expr */ yytestcase(yyruleno==298);
 { yygotominor.yy132 = yymsp[0].minor.yy346.pExpr; }
         break;
-      case 277: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+      case 278: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
 {
   assert( yymsp[-2].minor.yy473!=0 );
   yymsp[-2].minor.yy473->pLast->pNext = yymsp[-1].minor.yy473;
@@ -127803,14 +129144,14 @@ static void yy_reduce(
   yygotominor.yy473 = yymsp[-2].minor.yy473;
 }
         break;
-      case 278: /* trigger_cmd_list ::= trigger_cmd SEMI */
+      case 279: /* trigger_cmd_list ::= trigger_cmd SEMI */
 { 
   assert( yymsp[-1].minor.yy473!=0 );
   yymsp[-1].minor.yy473->pLast = yymsp[-1].minor.yy473;
   yygotominor.yy473 = yymsp[-1].minor.yy473;
 }
         break;
-      case 280: /* trnm ::= nm DOT nm */
+      case 281: /* trnm ::= nm DOT nm */
 {
   yygotominor.yy0 = yymsp[0].minor.yy0;
   sqlite3ErrorMsg(pParse, 
@@ -127818,33 +129159,33 @@ static void yy_reduce(
         "statements within triggers");
 }
         break;
-      case 282: /* tridxby ::= INDEXED BY nm */
+      case 283: /* tridxby ::= INDEXED BY nm */
 {
   sqlite3ErrorMsg(pParse,
         "the INDEXED BY clause is not allowed on UPDATE or DELETE statements "
         "within triggers");
 }
         break;
-      case 283: /* tridxby ::= NOT INDEXED */
+      case 284: /* tridxby ::= NOT INDEXED */
 {
   sqlite3ErrorMsg(pParse,
         "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements "
         "within triggers");
 }
         break;
-      case 284: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */
+      case 285: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */
 { yygotominor.yy473 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-4].minor.yy0, yymsp[-1].minor.yy14, yymsp[0].minor.yy132, yymsp[-5].minor.yy186); }
         break;
-      case 285: /* trigger_cmd ::= insert_cmd INTO trnm inscollist_opt select */
+      case 286: /* trigger_cmd ::= insert_cmd INTO trnm idlist_opt select */
 {yygotominor.yy473 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy408, yymsp[0].minor.yy3, yymsp[-4].minor.yy186);}
         break;
-      case 286: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */
+      case 287: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */
 {yygotominor.yy473 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy132);}
         break;
-      case 287: /* trigger_cmd ::= select */
+      case 288: /* trigger_cmd ::= select */
 {yygotominor.yy473 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy3); }
         break;
-      case 288: /* expr ::= RAISE LP IGNORE RP */
+      case 289: /* expr ::= RAISE LP IGNORE RP */
 {
   yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0); 
   if( yygotominor.yy346.pExpr ){
@@ -127854,7 +129195,7 @@ static void yy_reduce(
   yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
 }
         break;
-      case 289: /* expr ::= RAISE LP raisetype COMMA nm RP */
+      case 290: /* expr ::= RAISE LP raisetype COMMA nm RP */
 {
   yygotominor.yy346.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &yymsp[-1].minor.yy0); 
   if( yygotominor.yy346.pExpr ) {
@@ -127864,87 +129205,87 @@ static void yy_reduce(
   yygotominor.yy346.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
 }
         break;
-      case 290: /* raisetype ::= ROLLBACK */
+      case 291: /* raisetype ::= ROLLBACK */
 {yygotominor.yy328 = OE_Rollback;}
         break;
-      case 292: /* raisetype ::= FAIL */
+      case 293: /* raisetype ::= FAIL */
 {yygotominor.yy328 = OE_Fail;}
         break;
-      case 293: /* cmd ::= DROP TRIGGER ifexists fullname */
+      case 294: /* cmd ::= DROP TRIGGER ifexists fullname */
 {
   sqlite3DropTrigger(pParse,yymsp[0].minor.yy65,yymsp[-1].minor.yy328);
 }
         break;
-      case 294: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+      case 295: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
 {
   sqlite3Attach(pParse, yymsp[-3].minor.yy346.pExpr, yymsp[-1].minor.yy346.pExpr, yymsp[0].minor.yy132);
 }
         break;
-      case 295: /* cmd ::= DETACH database_kw_opt expr */
+      case 296: /* cmd ::= DETACH database_kw_opt expr */
 {
   sqlite3Detach(pParse, yymsp[0].minor.yy346.pExpr);
 }
         break;
-      case 300: /* cmd ::= REINDEX */
+      case 301: /* cmd ::= REINDEX */
 {sqlite3Reindex(pParse, 0, 0);}
         break;
-      case 301: /* cmd ::= REINDEX nm dbnm */
+      case 302: /* cmd ::= REINDEX nm dbnm */
 {sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
         break;
-      case 302: /* cmd ::= ANALYZE */
+      case 303: /* cmd ::= ANALYZE */
 {sqlite3Analyze(pParse, 0, 0);}
         break;
-      case 303: /* cmd ::= ANALYZE nm dbnm */
+      case 304: /* cmd ::= ANALYZE nm dbnm */
 {sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
         break;
-      case 304: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
+      case 305: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
 {
   sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy65,&yymsp[0].minor.yy0);
 }
         break;
-      case 305: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column */
+      case 306: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column */
 {
   sqlite3AlterFinishAddColumn(pParse, &yymsp[0].minor.yy0);
 }
         break;
-      case 306: /* add_column_fullname ::= fullname */
+      case 307: /* add_column_fullname ::= fullname */
 {
   pParse->db->lookaside.bEnabled = 0;
   sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy65);
 }
         break;
-      case 309: /* cmd ::= create_vtab */
+      case 310: /* cmd ::= create_vtab */
 {sqlite3VtabFinishParse(pParse,0);}
         break;
-      case 310: /* cmd ::= create_vtab LP vtabarglist RP */
+      case 311: /* cmd ::= create_vtab LP vtabarglist RP */
 {sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);}
         break;
-      case 311: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
+      case 312: /* 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.yy328);
 }
         break;
-      case 314: /* vtabarg ::= */
+      case 315: /* vtabarg ::= */
 {sqlite3VtabArgInit(pParse);}
         break;
-      case 316: /* vtabargtoken ::= ANY */
-      case 317: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==317);
-      case 318: /* lp ::= LP */ yytestcase(yyruleno==318);
+      case 317: /* vtabargtoken ::= ANY */
+      case 318: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==318);
+      case 319: /* lp ::= LP */ yytestcase(yyruleno==319);
 {sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);}
         break;
-      case 322: /* with ::= */
+      case 323: /* with ::= */
 {yygotominor.yy59 = 0;}
         break;
-      case 323: /* with ::= WITH wqlist */
-      case 324: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==324);
+      case 324: /* with ::= WITH wqlist */
+      case 325: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==325);
 { yygotominor.yy59 = yymsp[0].minor.yy59; }
         break;
-      case 325: /* wqlist ::= nm idxlist_opt AS LP select RP */
+      case 326: /* wqlist ::= nm eidlist_opt AS LP select RP */
 {
   yygotominor.yy59 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy14, yymsp[-1].minor.yy3);
 }
         break;
-      case 326: /* wqlist ::= wqlist COMMA nm idxlist_opt AS LP select RP */
+      case 327: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
 {
   yygotominor.yy59 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy59, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy14, yymsp[-1].minor.yy3);
 }
@@ -127972,19 +129313,19 @@ static void yy_reduce(
       /* (88) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==88);
       /* (89) conslist ::= tcons */ yytestcase(yyruleno==89);
       /* (91) tconscomma ::= */ yytestcase(yyruleno==91);
-      /* (273) foreach_clause ::= */ yytestcase(yyruleno==273);
-      /* (274) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==274);
-      /* (281) tridxby ::= */ yytestcase(yyruleno==281);
-      /* (298) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==298);
-      /* (299) database_kw_opt ::= */ yytestcase(yyruleno==299);
-      /* (307) kwcolumn_opt ::= */ yytestcase(yyruleno==307);
-      /* (308) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==308);
-      /* (312) vtabarglist ::= vtabarg */ yytestcase(yyruleno==312);
-      /* (313) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==313);
-      /* (315) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==315);
-      /* (319) anylist ::= */ yytestcase(yyruleno==319);
-      /* (320) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==320);
-      /* (321) anylist ::= anylist ANY */ yytestcase(yyruleno==321);
+      /* (274) foreach_clause ::= */ yytestcase(yyruleno==274);
+      /* (275) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==275);
+      /* (282) tridxby ::= */ yytestcase(yyruleno==282);
+      /* (299) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==299);
+      /* (300) database_kw_opt ::= */ yytestcase(yyruleno==300);
+      /* (308) kwcolumn_opt ::= */ yytestcase(yyruleno==308);
+      /* (309) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==309);
+      /* (313) vtabarglist ::= vtabarg */ yytestcase(yyruleno==313);
+      /* (314) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==314);
+      /* (316) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==316);
+      /* (320) anylist ::= */ yytestcase(yyruleno==320);
+      /* (321) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==321);
+      /* (322) anylist ::= anylist ANY */ yytestcase(yyruleno==322);
         break;
   };
   assert( yyruleno>=0 && yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) );
@@ -127992,9 +129333,9 @@ static void yy_reduce(
   yysize = yyRuleInfo[yyruleno].nrhs;
   yypParser->yyidx -= yysize;
   yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto);
-  if( yyact < YYNSTATE ){
-#ifdef NDEBUG
-    /* If we are not debugging and the reduce action popped at least
+  if( yyact <= YY_MAX_SHIFTREDUCE ){
+    if( yyact>YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
+    /* If the reduce action popped at least
     ** one element off the stack, then we can push the new element back
     ** onto the stack here, and skip the stack overflow test in yy_shift().
     ** That gives a significant speed improvement. */
@@ -128004,13 +129345,12 @@ static void yy_reduce(
       yymsp->stateno = (YYACTIONTYPE)yyact;
       yymsp->major = (YYCODETYPE)yygoto;
       yymsp->minor = yygotominor;
-    }else
-#endif
-    {
+      yyTraceShift(yypParser, yyact);
+    }else{
       yy_shift(yypParser,yyact,yygoto,&yygotominor);
     }
   }else{
-    assert( yyact == YYNSTATE + YYNRULE + 1 );
+    assert( yyact == YY_ACCEPT_ACTION );
     yy_accept(yypParser);
   }
 }
@@ -128135,12 +129475,13 @@ SQLITE_PRIVATE void sqlite3Parser(
 
   do{
     yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
-    if( yyact<YYNSTATE ){
+    if( yyact <= YY_MAX_SHIFTREDUCE ){
+      if( yyact > YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
       yy_shift(yypParser,yyact,yymajor,&yyminorunion);
       yypParser->yyerrcnt--;
       yymajor = YYNOCODE;
-    }else if( yyact < YYNSTATE + YYNRULE ){
-      yy_reduce(yypParser,yyact-YYNSTATE);
+    }else if( yyact <= YY_MAX_REDUCE ){
+      yy_reduce(yypParser,yyact-YY_MIN_REDUCE);
     }else{
       assert( yyact == YY_ERROR_ACTION );
 #ifdef YYERRORSYMBOL
@@ -128190,7 +129531,7 @@ SQLITE_PRIVATE void sqlite3Parser(
           yymx != YYERRORSYMBOL &&
           (yyact = yy_find_reduce_action(
                         yypParser->yystack[yypParser->yyidx].stateno,
-                        YYERRORSYMBOL)) >= YYNSTATE
+                        YYERRORSYMBOL)) >= YY_MIN_REDUCE
         ){
           yy_pop_parser_stack(yypParser);
         }
@@ -128240,6 +129581,11 @@ SQLITE_PRIVATE void sqlite3Parser(
 #endif
     }
   }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
+#ifndef NDEBUG
+  if( yyTraceFILE ){
+    fprintf(yyTraceFILE,"%sReturn\n",yyTracePrompt);
+  }
+#endif
   return;
 }
 
@@ -128928,6 +130274,7 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
   pParse->zTail = zSql;
   i = 0;
   assert( pzErrMsg!=0 );
+  /* sqlite3ParserTrace(stdout, "parser: "); */
   pEngine = sqlite3ParserAlloc(sqlite3Malloc);
   if( pEngine==0 ){
     db->mallocFailed = 1;
@@ -129465,6 +130812,12 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db);
 /************** End of sqliteicu.h *******************************************/
 /************** Continuing where we left off in main.c ***********************/
 #endif
+#ifdef SQLITE_ENABLE_JSON1
+SQLITE_PRIVATE int sqlite3Json1Init(sqlite3*);
+#endif
+#ifdef SQLITE_ENABLE_FTS5
+SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3*);
+#endif
 
 #ifndef SQLITE_AMALGAMATION
 /* IMPLEMENTATION-OF: R-46656-45156 The sqlite3_version[] string constant
@@ -130372,17 +131725,23 @@ static void functionDestroy(sqlite3 *db, FuncDef *p){
 static void disconnectAllVtab(sqlite3 *db){
 #ifndef SQLITE_OMIT_VIRTUALTABLE
   int i;
+  HashElem *p;
   sqlite3BtreeEnterAll(db);
   for(i=0; i<db->nDb; i++){
     Schema *pSchema = db->aDb[i].pSchema;
     if( db->aDb[i].pSchema ){
-      HashElem *p;
       for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
         Table *pTab = (Table *)sqliteHashData(p);
         if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab);
       }
     }
   }
+  for(p=sqliteHashFirst(&db->aModule); p; p=sqliteHashNext(p)){
+    Module *pMod = (Module *)sqliteHashData(p);
+    if( pMod->pEpoTab ){
+      sqlite3VtabDisconnect(db, pMod->pEpoTab);
+    }
+  }
   sqlite3VtabUnlockList(db);
   sqlite3BtreeLeaveAll(db);
 #else
@@ -130560,6 +131919,7 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
     if( pMod->xDestroy ){
       pMod->xDestroy(pMod->pAux);
     }
+    sqlite3VtabEponymousTableClear(db, pMod);
     sqlite3DbFree(db, pMod);
   }
   sqlite3HashClear(&db->aModule);
@@ -132305,12 +133665,18 @@ static int openDatabase(
   }
 #endif
 
-#ifdef SQLITE_ENABLE_FTS3
+#ifdef SQLITE_ENABLE_FTS3 /* automatically defined by SQLITE_ENABLE_FTS4 */
   if( !db->mallocFailed && rc==SQLITE_OK ){
     rc = sqlite3Fts3Init(db);
   }
 #endif
 
+#ifdef SQLITE_ENABLE_FTS5
+  if( !db->mallocFailed && rc==SQLITE_OK ){
+    rc = sqlite3Fts5Init(db);
+  }
+#endif
+
 #ifdef SQLITE_ENABLE_ICU
   if( !db->mallocFailed && rc==SQLITE_OK ){
     rc = sqlite3IcuInit(db);
@@ -132329,6 +133695,12 @@ static int openDatabase(
   }
 #endif
 
+#ifdef SQLITE_ENABLE_JSON1
+  if( !db->mallocFailed && rc==SQLITE_OK){
+    rc = sqlite3Json1Init(db);
+  }
+#endif
+
   /* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking
   ** mode.  -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking
   ** mode.  Doing nothing at all also makes NORMAL the default.
@@ -134403,6 +135775,7 @@ struct Fts3Table {
   int nPendingData;               /* Current bytes of pending data */
   sqlite_int64 iPrevDocid;        /* Docid of most recently inserted document */
   int iPrevLangid;                /* Langid of recently inserted document */
+  int bPrevDelete;                /* True if last operation was a delete */
 
 #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
   /* State variables used for validating that the transaction control
@@ -135978,6 +137351,19 @@ static void fts3SetEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){
 #endif
 }
 
+/*
+** Set the SQLITE_INDEX_SCAN_UNIQUE flag in pIdxInfo->flags. Unless this
+** extension is currently being used by a version of SQLite too old to
+** support index-info flags. In that case this function is a no-op.
+*/
+static void fts3SetUniqueFlag(sqlite3_index_info *pIdxInfo){
+#if SQLITE_VERSION_NUMBER>=3008012
+  if( sqlite3_libversion_number()>=3008012 ){
+    pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE;
+  }
+#endif
+}
+
 /* 
 ** Implementation of the xBestIndex method for FTS3 tables. There
 ** are three possible strategies, in order of preference:
@@ -136068,6 +137454,9 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
     }
   }
 
+  /* If using a docid=? or rowid=? strategy, set the UNIQUE flag. */
+  if( pInfo->idxNum==FTS3_DOCID_SEARCH ) fts3SetUniqueFlag(pInfo);
+
   iIdx = 1;
   if( iCons>=0 ){
     pInfo->aConstraintUsage[iCons].argvIndex = iIdx++;
@@ -141718,125 +143107,151 @@ static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){
     rc = SQLITE_ERROR;
   }
 
-  if( rc==SQLITE_OK && (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){
-    Fts3Expr **apLeaf;
-    apLeaf = (Fts3Expr **)sqlite3_malloc(sizeof(Fts3Expr *) * nMaxDepth);
-    if( 0==apLeaf ){
-      rc = SQLITE_NOMEM;
-    }else{
-      memset(apLeaf, 0, sizeof(Fts3Expr *) * nMaxDepth);
-    }
-
-    if( rc==SQLITE_OK ){
-      int i;
-      Fts3Expr *p;
-
-      /* Set $p to point to the left-most leaf in the tree of eType nodes. */
-      for(p=pRoot; p->eType==eType; p=p->pLeft){
-        assert( p->pParent==0 || p->pParent->pLeft==p );
-        assert( p->pLeft && p->pRight );
+  if( rc==SQLITE_OK ){
+    if( (eType==FTSQUERY_AND || eType==FTSQUERY_OR) ){
+      Fts3Expr **apLeaf;
+      apLeaf = (Fts3Expr **)sqlite3_malloc(sizeof(Fts3Expr *) * nMaxDepth);
+      if( 0==apLeaf ){
+        rc = SQLITE_NOMEM;
+      }else{
+        memset(apLeaf, 0, sizeof(Fts3Expr *) * nMaxDepth);
       }
 
-      /* This loop runs once for each leaf in the tree of eType nodes. */
-      while( 1 ){
-        int iLvl;
-        Fts3Expr *pParent = p->pParent;     /* Current parent of p */
+      if( rc==SQLITE_OK ){
+        int i;
+        Fts3Expr *p;
 
-        assert( pParent==0 || pParent->pLeft==p );
-        p->pParent = 0;
-        if( pParent ){
-          pParent->pLeft = 0;
-        }else{
-          pRoot = 0;
+        /* Set $p to point to the left-most leaf in the tree of eType nodes. */
+        for(p=pRoot; p->eType==eType; p=p->pLeft){
+          assert( p->pParent==0 || p->pParent->pLeft==p );
+          assert( p->pLeft && p->pRight );
         }
-        rc = fts3ExprBalance(&p, nMaxDepth-1);
-        if( rc!=SQLITE_OK ) break;
 
-        for(iLvl=0; p && iLvl<nMaxDepth; iLvl++){
-          if( apLeaf[iLvl]==0 ){
-            apLeaf[iLvl] = p;
-            p = 0;
+        /* This loop runs once for each leaf in the tree of eType nodes. */
+        while( 1 ){
+          int iLvl;
+          Fts3Expr *pParent = p->pParent;     /* Current parent of p */
+
+          assert( pParent==0 || pParent->pLeft==p );
+          p->pParent = 0;
+          if( pParent ){
+            pParent->pLeft = 0;
           }else{
-            assert( pFree );
-            pFree->pLeft = apLeaf[iLvl];
-            pFree->pRight = p;
-            pFree->pLeft->pParent = pFree;
-            pFree->pRight->pParent = pFree;
-
-            p = pFree;
-            pFree = pFree->pParent;
-            p->pParent = 0;
-            apLeaf[iLvl] = 0;
+            pRoot = 0;
           }
-        }
-        if( p ){
-          sqlite3Fts3ExprFree(p);
-          rc = SQLITE_TOOBIG;
-          break;
-        }
-
-        /* If that was the last leaf node, break out of the loop */
-        if( pParent==0 ) break;
-
-        /* Set $p to point to the next leaf in the tree of eType nodes */
-        for(p=pParent->pRight; p->eType==eType; p=p->pLeft);
-
-        /* Remove pParent from the original tree. */
-        assert( pParent->pParent==0 || pParent->pParent->pLeft==pParent );
-        pParent->pRight->pParent = pParent->pParent;
-        if( pParent->pParent ){
-          pParent->pParent->pLeft = pParent->pRight;
-        }else{
-          assert( pParent==pRoot );
-          pRoot = pParent->pRight;
-        }
-
-        /* Link pParent into the free node list. It will be used as an
-        ** internal node of the new tree.  */
-        pParent->pParent = pFree;
-        pFree = pParent;
-      }
+          rc = fts3ExprBalance(&p, nMaxDepth-1);
+          if( rc!=SQLITE_OK ) break;
 
-      if( rc==SQLITE_OK ){
-        p = 0;
-        for(i=0; i<nMaxDepth; i++){
-          if( apLeaf[i] ){
-            if( p==0 ){
-              p = apLeaf[i];
-              p->pParent = 0;
+          for(iLvl=0; p && iLvl<nMaxDepth; iLvl++){
+            if( apLeaf[iLvl]==0 ){
+              apLeaf[iLvl] = p;
+              p = 0;
             }else{
-              assert( pFree!=0 );
+              assert( pFree );
+              pFree->pLeft = apLeaf[iLvl];
               pFree->pRight = p;
-              pFree->pLeft = apLeaf[i];
               pFree->pLeft->pParent = pFree;
               pFree->pRight->pParent = pFree;
 
               p = pFree;
               pFree = pFree->pParent;
               p->pParent = 0;
+              apLeaf[iLvl] = 0;
             }
           }
+          if( p ){
+            sqlite3Fts3ExprFree(p);
+            rc = SQLITE_TOOBIG;
+            break;
+          }
+
+          /* If that was the last leaf node, break out of the loop */
+          if( pParent==0 ) break;
+
+          /* Set $p to point to the next leaf in the tree of eType nodes */
+          for(p=pParent->pRight; p->eType==eType; p=p->pLeft);
+
+          /* Remove pParent from the original tree. */
+          assert( pParent->pParent==0 || pParent->pParent->pLeft==pParent );
+          pParent->pRight->pParent = pParent->pParent;
+          if( pParent->pParent ){
+            pParent->pParent->pLeft = pParent->pRight;
+          }else{
+            assert( pParent==pRoot );
+            pRoot = pParent->pRight;
+          }
+
+          /* Link pParent into the free node list. It will be used as an
+          ** internal node of the new tree.  */
+          pParent->pParent = pFree;
+          pFree = pParent;
         }
-        pRoot = p;
-      }else{
-        /* An error occurred. Delete the contents of the apLeaf[] array 
-        ** and pFree list. Everything else is cleaned up by the call to
-        ** sqlite3Fts3ExprFree(pRoot) below.  */
-        Fts3Expr *pDel;
-        for(i=0; i<nMaxDepth; i++){
-          sqlite3Fts3ExprFree(apLeaf[i]);
-        }
-        while( (pDel=pFree)!=0 ){
-          pFree = pDel->pParent;
-          sqlite3_free(pDel);
+
+        if( rc==SQLITE_OK ){
+          p = 0;
+          for(i=0; i<nMaxDepth; i++){
+            if( apLeaf[i] ){
+              if( p==0 ){
+                p = apLeaf[i];
+                p->pParent = 0;
+              }else{
+                assert( pFree!=0 );
+                pFree->pRight = p;
+                pFree->pLeft = apLeaf[i];
+                pFree->pLeft->pParent = pFree;
+                pFree->pRight->pParent = pFree;
+
+                p = pFree;
+                pFree = pFree->pParent;
+                p->pParent = 0;
+              }
+            }
+          }
+          pRoot = p;
+        }else{
+          /* An error occurred. Delete the contents of the apLeaf[] array 
+          ** and pFree list. Everything else is cleaned up by the call to
+          ** sqlite3Fts3ExprFree(pRoot) below.  */
+          Fts3Expr *pDel;
+          for(i=0; i<nMaxDepth; i++){
+            sqlite3Fts3ExprFree(apLeaf[i]);
+          }
+          while( (pDel=pFree)!=0 ){
+            pFree = pDel->pParent;
+            sqlite3_free(pDel);
+          }
         }
+
+        assert( pFree==0 );
+        sqlite3_free( apLeaf );
+      }
+    }else if( eType==FTSQUERY_NOT ){
+      Fts3Expr *pLeft = pRoot->pLeft;
+      Fts3Expr *pRight = pRoot->pRight;
+
+      pRoot->pLeft = 0;
+      pRoot->pRight = 0;
+      pLeft->pParent = 0;
+      pRight->pParent = 0;
+
+      rc = fts3ExprBalance(&pLeft, nMaxDepth-1);
+      if( rc==SQLITE_OK ){
+        rc = fts3ExprBalance(&pRight, nMaxDepth-1);
       }
 
-      assert( pFree==0 );
-      sqlite3_free( apLeaf );
+      if( rc!=SQLITE_OK ){
+        sqlite3Fts3ExprFree(pRight);
+        sqlite3Fts3ExprFree(pLeft);
+      }else{
+        assert( pLeft && pRight );
+        pRoot->pLeft = pLeft;
+        pLeft->pParent = pRoot;
+        pRoot->pRight = pRight;
+        pRight->pParent = pRoot;
+      }
     }
   }
-
+  
   if( rc!=SQLITE_OK ){
     sqlite3Fts3ExprFree(pRoot);
     pRoot = 0;
@@ -145313,10 +146728,12 @@ static int fts3PendingTermsAdd(
 */
 static int fts3PendingTermsDocid(
   Fts3Table *p,                   /* Full-text table handle */
+  int bDelete,                    /* True if this op is a delete */
   int iLangid,                    /* Language id of row being written */
   sqlite_int64 iDocid             /* Docid of row being written */
 ){
   assert( iLangid>=0 );
+  assert( bDelete==1 || bDelete==0 );
 
   /* TODO(shess) Explore whether partially flushing the buffer on
   ** forced-flush would provide better performance.  I suspect that if
@@ -145324,7 +146741,8 @@ static int fts3PendingTermsDocid(
   ** buffer was half empty, that would let the less frequent terms
   ** generate longer doclists.
   */
-  if( iDocid<=p->iPrevDocid 
+  if( iDocid<p->iPrevDocid 
+   || (iDocid==p->iPrevDocid && p->bPrevDelete==0)
    || p->iPrevLangid!=iLangid
    || p->nPendingData>p->nMaxPendingData 
   ){
@@ -145333,6 +146751,7 @@ static int fts3PendingTermsDocid(
   }
   p->iPrevDocid = iDocid;
   p->iPrevLangid = iLangid;
+  p->bPrevDelete = bDelete;
   return SQLITE_OK;
 }
 
@@ -145522,7 +146941,8 @@ static void fts3DeleteTerms(
     if( SQLITE_ROW==sqlite3_step(pSelect) ){
       int i;
       int iLangid = langidFromSelect(p, pSelect);
-      rc = fts3PendingTermsDocid(p, iLangid, sqlite3_column_int64(pSelect, 0));
+      i64 iDocid = sqlite3_column_int64(pSelect, 0);
+      rc = fts3PendingTermsDocid(p, 1, iLangid, iDocid);
       for(i=1; rc==SQLITE_OK && i<=p->nColumn; i++){
         int iCol = i-1;
         if( p->abNotindexed[iCol]==0 ){
@@ -145770,14 +147190,19 @@ static int fts3SegReaderNext(
 
     if( fts3SegReaderIsPending(pReader) ){
       Fts3HashElem *pElem = *(pReader->ppNextElem);
-      if( pElem==0 ){
-        pReader->aNode = 0;
-      }else{
+      sqlite3_free(pReader->aNode);
+      pReader->aNode = 0;
+      if( pElem ){
+        char *aCopy;
         PendingList *pList = (PendingList *)fts3HashData(pElem);
+        int nCopy = pList->nData+1;
         pReader->zTerm = (char *)fts3HashKey(pElem);
         pReader->nTerm = fts3HashKeysize(pElem);
-        pReader->nNode = pReader->nDoclist = pList->nData + 1;
-        pReader->aNode = pReader->aDoclist = pList->aData;
+        aCopy = (char*)sqlite3_malloc(nCopy);
+        if( !aCopy ) return SQLITE_NOMEM;
+        memcpy(aCopy, pList->aData, nCopy);
+        pReader->nNode = pReader->nDoclist = nCopy;
+        pReader->aNode = pReader->aDoclist = aCopy;
         pReader->ppNextElem++;
         assert( pReader->aNode );
       }
@@ -146017,12 +147442,14 @@ SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(
 ** second argument.
 */
 SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){
-  if( pReader && !fts3SegReaderIsPending(pReader) ){
-    sqlite3_free(pReader->zTerm);
+  if( pReader ){
+    if( !fts3SegReaderIsPending(pReader) ){
+      sqlite3_free(pReader->zTerm);
+    }
     if( !fts3SegReaderIsRootOnly(pReader) ){
       sqlite3_free(pReader->aNode);
-      sqlite3_blob_close(pReader->pBlob);
     }
+    sqlite3_blob_close(pReader->pBlob);
   }
   sqlite3_free(pReader);
 }
@@ -147965,7 +149392,7 @@ static int fts3DoRebuild(Fts3Table *p){
     while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
       int iCol;
       int iLangid = langidFromSelect(p, pStmt);
-      rc = fts3PendingTermsDocid(p, iLangid, sqlite3_column_int64(pStmt, 0));
+      rc = fts3PendingTermsDocid(p, 0, iLangid, sqlite3_column_int64(pStmt, 0));
       memset(aSz, 0, sizeof(aSz[0]) * (p->nColumn+1));
       for(iCol=0; rc==SQLITE_OK && iCol<p->nColumn; iCol++){
         if( p->abNotindexed[iCol]==0 ){
@@ -150070,7 +151497,7 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
       }
     }
     if( rc==SQLITE_OK && (!isRemove || *pRowid!=p->iPrevDocid ) ){
-      rc = fts3PendingTermsDocid(p, iLangid, *pRowid);
+      rc = fts3PendingTermsDocid(p, 0, iLangid, *pRowid);
     }
     if( rc==SQLITE_OK ){
       assert( p->iPrevDocid==*pRowid );
@@ -156964,10 +158391,6 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
 /* #include <string.h> */
 /* #include <stdio.h> */
 
-#if !defined(_WIN32)
-/* #  include <unistd.h> */
-#endif
-
 /* #include "sqlite3.h" */
 
 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU)
@@ -157072,6 +158495,18 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
 **
 ** The order of the columns in the data_% table does not matter.
 **
+** Instead of a regular table, the RBU database may also contain virtual
+** tables or view named using the data_<target> naming scheme. 
+**
+** 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 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 
@@ -157152,6 +158587,14 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
 **
 **   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:
@@ -157224,6 +158667,10 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
 
 /* #include "sqlite3.h"              ** Required for error code definitions ** */
 
+#if 0
+extern "C" {
+#endif
+
 typedef struct sqlite3rbu sqlite3rbu;
 
 /*
@@ -157309,6 +158756,18 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3rbu_db(sqlite3rbu*, int bRbu);
 */
 SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *pRbu);
 
+/*
+** Force RBU to save its state to disk.
+**
+** If a power failure or application crash occurs during an update, following
+** system recovery RBU may resume the update from the point at which the state
+** was last saved. In other words, from the most recent successful call to 
+** sqlite3rbu_close() or this function.
+**
+** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
+*/
+SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *pRbu);
+
 /*
 ** Close an RBU handle. 
 **
@@ -157390,11 +158849,19 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const cha
 */
 SQLITE_API void SQLITE_STDCALL 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
 
@@ -157541,6 +159008,7 @@ struct RbuObjIter {
   /* 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 */
@@ -157551,7 +159019,7 @@ struct RbuObjIter {
   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_$zTbl */
+  sqlite3_stmt *pTmpInsert;       /* Insert into rbu_tmp_$zDataTbl */
 
   /* Last UPDATE used (for PK b-tree updates only), or NULL. */
   RbuUpdateStmt *pRbuUpdate;
@@ -157662,6 +159130,252 @@ struct rbu_file {
 };
 
 
+/*************************************************************************
+** The following three functions, found below:
+**
+**   rbuDeltaGetInt()
+**   rbuDeltaChecksum()
+**   rbuDeltaApply()
+**
+** are lifted from the fossil source code (http://fossil-scm.org). They
+** are used to implement the scalar SQL function rbu_fossil_delta().
+*/
+
+/*
+** Read bytes from *pz and convert them into a positive integer.  When
+** finished, leave *pz pointing to the first character past the end of
+** the integer.  The *pLen parameter holds the length of the string
+** in *pz and is decremented once for each character in the integer.
+*/
+static unsigned int rbuDeltaGetInt(const char **pz, int *pLen){
+  static const signed char zValue[] = {
+    -1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1,
+     0,  1,  2,  3,  4,  5,  6,  7,    8,  9, -1, -1, -1, -1, -1, -1,
+    -1, 10, 11, 12, 13, 14, 15, 16,   17, 18, 19, 20, 21, 22, 23, 24,
+    25, 26, 27, 28, 29, 30, 31, 32,   33, 34, 35, -1, -1, -1, -1, 36,
+    -1, 37, 38, 39, 40, 41, 42, 43,   44, 45, 46, 47, 48, 49, 50, 51,
+    52, 53, 54, 55, 56, 57, 58, 59,   60, 61, 62, -1, -1, -1, 63, -1,
+  };
+  unsigned int v = 0;
+  int c;
+  unsigned char *z = (unsigned char*)*pz;
+  unsigned char *zStart = z;
+  while( (c = zValue[0x7f&*(z++)])>=0 ){
+     v = (v<<6) + c;
+  }
+  z--;
+  *pLen -= z - zStart;
+  *pz = (char*)z;
+  return v;
+}
+
+/*
+** Compute a 32-bit checksum on the N-byte buffer.  Return the result.
+*/
+static unsigned int rbuDeltaChecksum(const char *zIn, size_t N){
+  const unsigned char *z = (const unsigned char *)zIn;
+  unsigned sum0 = 0;
+  unsigned sum1 = 0;
+  unsigned sum2 = 0;
+  unsigned sum3 = 0;
+  while(N >= 16){
+    sum0 += ((unsigned)z[0] + z[4] + z[8] + z[12]);
+    sum1 += ((unsigned)z[1] + z[5] + z[9] + z[13]);
+    sum2 += ((unsigned)z[2] + z[6] + z[10]+ z[14]);
+    sum3 += ((unsigned)z[3] + z[7] + z[11]+ z[15]);
+    z += 16;
+    N -= 16;
+  }
+  while(N >= 4){
+    sum0 += z[0];
+    sum1 += z[1];
+    sum2 += z[2];
+    sum3 += z[3];
+    z += 4;
+    N -= 4;
+  }
+  sum3 += (sum2 << 8) + (sum1 << 16) + (sum0 << 24);
+  switch(N){
+    case 3:   sum3 += (z[2] << 8);
+    case 2:   sum3 += (z[1] << 16);
+    case 1:   sum3 += (z[0] << 24);
+    default:  ;
+  }
+  return sum3;
+}
+
+/*
+** Apply a delta.
+**
+** The output buffer should be big enough to hold the whole output
+** file and a NUL terminator at the end.  The delta_output_size()
+** routine will determine this size for you.
+**
+** The delta string should be null-terminated.  But the delta string
+** may contain embedded NUL characters (if the input and output are
+** binary files) so we also have to pass in the length of the delta in
+** the lenDelta parameter.
+**
+** This function returns the size of the output file in bytes (excluding
+** the final NUL terminator character).  Except, if the delta string is
+** malformed or intended for use with a source file other than zSrc,
+** then this routine returns -1.
+**
+** Refer to the delta_create() documentation above for a description
+** of the delta file format.
+*/
+static int rbuDeltaApply(
+  const char *zSrc,      /* The source or pattern file */
+  int lenSrc,            /* Length of the source file */
+  const char *zDelta,    /* Delta to apply to the pattern */
+  int lenDelta,          /* Length of the delta */
+  char *zOut             /* Write the output into this preallocated buffer */
+){
+  unsigned int limit;
+  unsigned int total = 0;
+#ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST
+  char *zOrigOut = zOut;
+#endif
+
+  limit = rbuDeltaGetInt(&zDelta, &lenDelta);
+  if( *zDelta!='\n' ){
+    /* ERROR: size integer not terminated by "\n" */
+    return -1;
+  }
+  zDelta++; lenDelta--;
+  while( *zDelta && lenDelta>0 ){
+    unsigned int cnt, ofst;
+    cnt = rbuDeltaGetInt(&zDelta, &lenDelta);
+    switch( zDelta[0] ){
+      case '@': {
+        zDelta++; lenDelta--;
+        ofst = rbuDeltaGetInt(&zDelta, &lenDelta);
+        if( lenDelta>0 && zDelta[0]!=',' ){
+          /* ERROR: copy command not terminated by ',' */
+          return -1;
+        }
+        zDelta++; lenDelta--;
+        total += cnt;
+        if( total>limit ){
+          /* ERROR: copy exceeds output file size */
+          return -1;
+        }
+        if( (int)(ofst+cnt) > lenSrc ){
+          /* ERROR: copy extends past end of input */
+          return -1;
+        }
+        memcpy(zOut, &zSrc[ofst], cnt);
+        zOut += cnt;
+        break;
+      }
+      case ':': {
+        zDelta++; lenDelta--;
+        total += cnt;
+        if( total>limit ){
+          /* ERROR:  insert command gives an output larger than predicted */
+          return -1;
+        }
+        if( (int)cnt>lenDelta ){
+          /* ERROR: insert count exceeds size of delta */
+          return -1;
+        }
+        memcpy(zOut, zDelta, cnt);
+        zOut += cnt;
+        zDelta += cnt;
+        lenDelta -= cnt;
+        break;
+      }
+      case ';': {
+        zDelta++; lenDelta--;
+        zOut[0] = 0;
+#ifndef FOSSIL_OMIT_DELTA_CKSUM_TEST
+        if( cnt!=rbuDeltaChecksum(zOrigOut, total) ){
+          /* ERROR:  bad checksum */
+          return -1;
+        }
+#endif
+        if( total!=limit ){
+          /* ERROR: generated size does not match predicted size */
+          return -1;
+        }
+        return total;
+      }
+      default: {
+        /* ERROR: unknown delta operator */
+        return -1;
+      }
+    }
+  }
+  /* ERROR: unterminated delta */
+  return -1;
+}
+
+static int rbuDeltaOutputSize(const char *zDelta, int lenDelta){
+  int size;
+  size = rbuDeltaGetInt(&zDelta, &lenDelta);
+  if( *zDelta!='\n' ){
+    /* ERROR: size integer not terminated by "\n" */
+    return -1;
+  }
+  return size;
+}
+
+/*
+** End of code taken from fossil.
+*************************************************************************/
+
+/*
+** Implementation of SQL scalar function rbu_fossil_delta().
+**
+** This function applies a fossil delta patch to a blob. Exactly two
+** arguments must be passed to this function. The first is the blob to
+** patch and the second the patch to apply. If no error occurs, this
+** function returns the patched blob.
+*/
+static void rbuFossilDeltaFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  const char *aDelta;
+  int nDelta;
+  const char *aOrig;
+  int nOrig;
+
+  int nOut;
+  int nOut2;
+  char *aOut;
+
+  assert( argc==2 );
+
+  nOrig = sqlite3_value_bytes(argv[0]);
+  aOrig = (const char*)sqlite3_value_blob(argv[0]);
+  nDelta = sqlite3_value_bytes(argv[1]);
+  aDelta = (const char*)sqlite3_value_blob(argv[1]);
+
+  /* Figure out the size of the output */
+  nOut = rbuDeltaOutputSize(aDelta, nDelta);
+  if( nOut<0 ){
+    sqlite3_result_error(context, "corrupt fossil delta", -1);
+    return;
+  }
+
+  aOut = sqlite3_malloc(nOut+1);
+  if( aOut==0 ){
+    sqlite3_result_error_nomem(context);
+  }else{
+    nOut2 = rbuDeltaApply(aOrig, nOrig, aDelta, nDelta, aOut);
+    if( nOut2!=nOut ){
+      sqlite3_result_error(context, "corrupt fossil delta", -1);
+    }else{
+      sqlite3_result_blob(context, aOut, nOut, sqlite3_free);
+    }
+  }
+}
+
+
 /*
 ** Prepare the SQL statement in buffer zSql against database handle db.
 ** If successful, set *ppStmt to point to the new statement and return
@@ -157828,7 +159542,8 @@ static int rbuObjIterNext(sqlite3rbu *p, RbuObjIter *pIter){
           pIter->zTbl = 0;
         }else{
           pIter->zTbl = (const char*)sqlite3_column_text(pIter->pTblIter, 0);
-          rc = pIter->zTbl ? SQLITE_OK : SQLITE_NOMEM;
+          pIter->zDataTbl = (const char*)sqlite3_column_text(pIter->pTblIter,1);
+          rc = (pIter->zDataTbl && pIter->zTbl) ? SQLITE_OK : SQLITE_NOMEM;
         }
       }else{
         if( pIter->zIdx==0 ){
@@ -157859,6 +159574,40 @@ static int rbuObjIterNext(sqlite3rbu *p, RbuObjIter *pIter){
   return rc;
 }
 
+
+/*
+** The implementation of the rbu_target_name() SQL function. This function
+** accepts one argument - the name of a table in the RBU database. If the
+** table name matches the pattern:
+**
+**     data[0-9]_<name>
+**
+** 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
+*/
+static void rbuTargetNameFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  const char *zIn;
+  assert( argc==1 );
+
+  zIn = (const char*)sqlite3_value_text(argv[0]);
+  if( zIn && 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(context, &zIn[i+1], -1, SQLITE_STATIC);
+    }
+  }
+}
+
 /*
 ** Initialize the iterator structure passed as the second argument.
 **
@@ -157872,8 +159621,9 @@ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){
   memset(pIter, 0, sizeof(RbuObjIter));
 
   rc = prepareAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg, 
-      "SELECT substr(name, 6) FROM sqlite_master "
-      "WHERE type IN ('table', 'view') AND name LIKE 'data_%'"
+      "SELECT rbu_target_name(name) AS target, name FROM sqlite_master "
+      "WHERE type IN ('table', 'view') AND target IS NOT NULL "
+      "ORDER BY name"
   );
 
   if( rc==SQLITE_OK ){
@@ -158140,7 +159890,7 @@ static void rbuTableType(
   }
 
 rbuTableType_end: {
-    int i;
+    unsigned int i;
     for(i=0; i<sizeof(aStmt)/sizeof(aStmt[0]); i++){
       rbuFinalize(p, aStmt[i]);
     }
@@ -158219,7 +159969,7 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
     ** 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 'data_%q'", pIter->zTbl)
+        sqlite3_mprintf("SELECT * FROM '%q'", pIter->zDataTbl)
     );
     if( p->rc==SQLITE_OK ){
       nCol = sqlite3_column_count(pStmt);
@@ -158244,7 +159994,7 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
     ){
       p->rc = SQLITE_ERROR;
       p->zErrmsg = sqlite3_mprintf(
-          "table data_%q %s rbu_rowid column", pIter->zTbl,
+          "table %q %s rbu_rowid column", pIter->zDataTbl,
           (bRbuRowid ? "may not have" : "requires")
       );
     }
@@ -158265,8 +160015,8 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
       }
       if( i==pIter->nTblCol ){
         p->rc = SQLITE_ERROR;
-        p->zErrmsg = sqlite3_mprintf("column missing from data_%q: %s",
-            pIter->zTbl, zName
+        p->zErrmsg = sqlite3_mprintf("column missing from %q: %s",
+            pIter->zDataTbl, zName
         );
       }else{
         int iPk = sqlite3_column_int(pStmt, 5);
@@ -158553,7 +160303,7 @@ static char *rbuObjIterGetSetlist(
   if( p->rc==SQLITE_OK ){
     int i;
 
-    if( strlen(zMask)!=pIter->nTblCol ){
+    if( (int)strlen(zMask)!=pIter->nTblCol ){
       rbuBadControlError(p);
     }else{
       const char *zSep = "";
@@ -158565,12 +160315,18 @@ static char *rbuObjIterGetSetlist(
           );
           zSep = ", ";
         }
-        if( c=='d' ){
+        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 = ", ";
+        }
       }
     }
   }
@@ -158821,7 +160577,7 @@ static void rbuObjIterPrepareTmpInsert(
     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->zTbl, zCollist, zRbuRowid, zBind
+          p->zStateDb, pIter->zDataTbl, zCollist, zRbuRowid, zBind
     ));
   }
 }
@@ -158917,18 +160673,18 @@ static int rbuObjIterPrepareAll(
         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->zTbl,
+              zCollist, p->zStateDb, pIter->zDataTbl,
               zCollist, zLimit
           );
         }else{
           zSql = sqlite3_mprintf(
-              "SELECT %s, rbu_control FROM 'data_%q' "
+              "SELECT %s, rbu_control FROM '%q' "
               "WHERE typeof(rbu_control)='integer' AND rbu_control!=1 "
               "UNION ALL "
               "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' "
               "ORDER BY %s%s",
-              zCollist, pIter->zTbl, 
-              zCollist, p->zStateDb, pIter->zTbl, 
+              zCollist, pIter->zDataTbl, 
+              zCollist, p->zStateDb, pIter->zDataTbl, 
               zCollist, zLimit
           );
         }
@@ -158952,16 +160708,6 @@ static int rbuObjIterPrepareAll(
       zCollist = rbuObjIterGetCollist(p, pIter);
       pIter->nCol = pIter->nTblCol;
 
-      /* Create the SELECT statement to read keys from data_xxx */
-      if( p->rc==SQLITE_OK ){
-        p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz,
-            sqlite3_mprintf(
-              "SELECT %s, rbu_control%s FROM 'data_%q'%s", 
-              zCollist, (bRbuRowid ? ", rbu_rowid" : ""), zTbl, zLimit
-            )
-        );
-      }
-
       /* Create the imposter table or tables (if required). */
       rbuCreateImposterTable(p, pIter);
       rbuCreateImposterTable2(p, pIter);
@@ -158995,10 +160741,10 @@ static int rbuObjIterPrepareAll(
         /* 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 'data_%q' WHERE 0;"
-            , p->zStateDb
-            , zTbl, (pIter->eType==RBU_PK_EXTERNAL ? ", 0 AS rbu_rowid" : "")
-            , zTbl
+            "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,
@@ -159034,6 +160780,17 @@ static int rbuObjIterPrepareAll(
         rbuObjIterPrepareTmpInsert(p, pIter, zCollist, zRbuRowid);
       }
 
+      /* Create the SELECT statement to read keys from data_xxx */
+      if( p->rc==SQLITE_OK ){
+        p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz,
+            sqlite3_mprintf(
+              "SELECT %s, rbu_control%s FROM '%q'%s", 
+              zCollist, (bRbuRowid ? ", rbu_rowid" : ""), 
+              pIter->zDataTbl, zLimit
+            )
+        );
+      }
+
       sqlite3_free(zWhere);
       sqlite3_free(zOldlist);
       sqlite3_free(zNewlist);
@@ -159164,6 +160921,18 @@ static void rbuOpenDatabase(sqlite3rbu *p){
     );
   }
 
+  if( p->rc==SQLITE_OK ){
+    p->rc = sqlite3_create_function(p->dbMain, 
+        "rbu_fossil_delta", 2, SQLITE_UTF8, 0, rbuFossilDeltaFunc, 0, 0
+    );
+  }
+
+  if( p->rc==SQLITE_OK ){
+    p->rc = sqlite3_create_function(p->dbRbu, 
+        "rbu_target_name", 1, SQLITE_UTF8, (void*)p, rbuTargetNameFunc, 0, 0
+    );
+  }
+
   if( p->rc==SQLITE_OK ){
     p->rc = sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_RBU, (void*)p);
   }
@@ -159386,6 +161155,30 @@ static void rbuLockDatabase(sqlite3rbu *p){
   }
 }
 
+#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_malloc( 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
+
 /*
 ** 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,
@@ -159420,10 +161213,37 @@ static void rbuMoveOalFile(sqlite3rbu *p){
       rbuObjIterFinalize(&p->objiter);
       sqlite3_close(p->dbMain);
       sqlite3_close(p->dbRbu);
+      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 ){
-        p->dbMain = 0;
-        p->dbRbu = 0;
         rbuOpenDatabase(p);
         rbuSetupCheckpoint(p, 0);
       }
@@ -159593,7 +161413,7 @@ static int rbuStep(sqlite3rbu *p){
         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=='x' || c=='d' ){
+          if( pIter->abTblPk[i] || c!='.' ){
             p->rc = sqlite3_bind_value(pUpdate, i+1, pVal);
           }
         }
@@ -159705,7 +161525,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *p){
             ** But the contents can be deleted.  */
             if( pIter->abIndexed ){
               rbuMPrintfExec(p, p->dbRbu, 
-                  "DELETE FROM %s.'rbu_tmp_%q'", p->zStateDb, pIter->zTbl
+                  "DELETE FROM %s.'rbu_tmp_%q'", p->zStateDb, pIter->zDataTbl
               );
             }
           }else{
@@ -159928,10 +161748,13 @@ static void rbuSetupOal(sqlite3rbu *p, RbuState *pState){
 ** leave an error code and error message in the rbu handle.
 */
 static void rbuDeleteOalFile(sqlite3rbu *p){
-  char *zOal = sqlite3_mprintf("%s-oal", p->zTarget);
-  assert( p->rc==SQLITE_OK && p->zErrmsg==0 );
-  unlink(zOal);
-  sqlite3_free(zOal);
+  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);
+  }
 }
 
 /*
@@ -160044,14 +161867,25 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
 
     if( p->rc==SQLITE_OK ){
       if( p->eStage==RBU_STAGE_OAL ){
+        sqlite3 *db = p->dbMain;
 
         /* Open transactions both databases. The *-oal file is opened or
         ** created at this point. */
-        p->rc = sqlite3_exec(p->dbMain, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
+        p->rc = sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
         if( p->rc==SQLITE_OK ){
           p->rc = sqlite3_exec(p->dbRbu, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
         }
-  
+
+        /* 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);
+          }
+        }
+
         /* Point the object iterator at the first object */
         if( p->rc==SQLITE_OK ){
           p->rc = rbuObjIterFirst(p, &p->objiter);
@@ -160165,6 +161999,32 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3rbu_progress(sqlite3rbu *pRbu){
   return pRbu->nProgress;
 }
 
+SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *p){
+  int rc = p->rc;
+  
+  if( rc==SQLITE_DONE ) return SQLITE_OK;
+
+  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);
+  }
+
+  p->rc = rc;
+  rbuSaveState(p, p->eStage);
+  rc = p->rc;
+
+  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);
+  }
+
+  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:
@@ -160644,7 +162504,8 @@ static int rbuVfsOpen(
     rbuVfsShmMap,                 /* xShmMap */
     rbuVfsShmLock,                /* xShmLock */
     rbuVfsShmBarrier,             /* xShmBarrier */
-    rbuVfsShmUnmap                /* xShmUnmap */
+    rbuVfsShmUnmap,               /* xShmUnmap */
+    0, 0                          /* xFetch, xUnfetch */
   };
   rbu_vfs *pRbuVfs = (rbu_vfs*)pVfs;
   sqlite3_vfs *pRealVfs = pRbuVfs->pRealVfs;
@@ -160986,6 +162847,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const cha
 ** 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.
 */
 
 /* #include "sqliteInt.h"   ** Requires access to internal data structures ** */
@@ -161034,7 +162898,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const cha
   "  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 */"                   \
+  "  pgsize     INTEGER,          /* Size of the page */"                   \
+  "  schema     TEXT HIDDEN       /* Database schema being analyzed */"     \
   ");"
 
 
@@ -161072,6 +162937,7 @@ 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 */
 
   StatPage aPage[32];
   int iPage;                      /* Current entry in aPage[] */
@@ -161149,9 +163015,32 @@ static int statDisconnect(sqlite3_vtab *pVtab){
 
 /*
 ** There is no "best-index". This virtual table always does a linear
-** scan of the binary VFS log file.
+** 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;
+
+  pIdxInfo->estimatedCost = 1.0e6;  /* Initial cost estimate */
+
+  /* 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;
+  }
+
 
   /* Records are always returned in ascending order of (name, path). 
   ** If this will satisfy the client, set the orderByConsumed flag so that 
@@ -161171,7 +163060,6 @@ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
     pIdxInfo->orderByConsumed = 1;
   }
 
-  pIdxInfo->estimatedCost = 10.0;
   return SQLITE_OK;
 }
 
@@ -161181,36 +163069,18 @@ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
 static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
   StatTable *pTab = (StatTable *)pVTab;
   StatCursor *pCsr;
-  int rc;
 
   pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor));
   if( pCsr==0 ){
-    rc = SQLITE_NOMEM;
+    return SQLITE_NOMEM;
   }else{
-    char *zSql;
     memset(pCsr, 0, sizeof(StatCursor));
     pCsr->base.pVtab = pVTab;
-
-    zSql = sqlite3_mprintf(
-        "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
-        "  UNION ALL  "
-        "SELECT name, rootpage, type"
-        "  FROM \"%w\".sqlite_master WHERE rootpage!=0"
-        "  ORDER BY name", pTab->db->aDb[pTab->iDb].zName);
-    if( zSql==0 ){
-      rc = SQLITE_NOMEM;
-    }else{
-      rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
-      sqlite3_free(zSql);
-    }
-    if( rc!=SQLITE_OK ){
-      sqlite3_free(pCsr);
-      pCsr = 0;
-    }
+    pCsr->iDb = pTab->iDb;
   }
 
   *ppCursor = (sqlite3_vtab_cursor *)pCsr;
-  return rc;
+  return SQLITE_OK;
 }
 
 static void statClearPage(StatPage *p){
@@ -161235,6 +163105,7 @@ static void statResetCsr(StatCursor *pCsr){
   pCsr->iPage = 0;
   sqlite3_free(pCsr->zPath);
   pCsr->zPath = 0;
+  pCsr->isEof = 0;
 }
 
 /*
@@ -161397,7 +163268,7 @@ static int statNext(sqlite3_vtab_cursor *pCursor){
   char *z;
   StatCursor *pCsr = (StatCursor *)pCursor;
   StatTable *pTab = (StatTable *)pCursor->pVtab;
-  Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
+  Btree *pBt = pTab->db->aDb[pCsr->iDb].pBt;
   Pager *pPager = sqlite3BtreePager(pBt);
 
   sqlite3_free(pCsr->zPath);
@@ -161535,9 +163406,43 @@ static int statFilter(
   int argc, sqlite3_value **argv
 ){
   StatCursor *pCsr = (StatCursor *)pCursor;
+  StatTable *pTab = (StatTable*)(pCursor->pVtab);
+  char *zSql;
+  int rc = SQLITE_OK;
+  char *zMaster;
 
+  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;
+    }
+  }else{
+    pCsr->iDb = pTab->iDb;
+  }
   statResetCsr(pCsr);
-  return statNext(pCursor);
+  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].zName, zMaster);
+  if( zSql==0 ){
+    return SQLITE_NOMEM;
+  }else{
+    rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
+    sqlite3_free(zSql);
+  }
+
+  if( rc==SQLITE_OK ){
+    rc = statNext(pCursor);
+  }
+  return rc;
 }
 
 static int statColumn(
@@ -161574,10 +163479,15 @@ static int statColumn(
     case 8:            /* pgoffset */
       sqlite3_result_int64(ctx, pCsr->iOffset);
       break;
-    default:           /* pgsize */
-      assert( i==9 );
+    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].zName, -1, SQLITE_STATIC);
+      break;
+    }
   }
   return SQLITE_OK;
 }
@@ -161621,3 +163531,20686 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; }
 #endif /* SQLITE_ENABLE_DBSTAT_VTAB */
 
 /************** End of dbstat.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.
+**
+******************************************************************************
+**
+** This SQLite extension implements JSON functions.  The interface is
+** modeled after MySQL JSON functions:
+**
+**     https://dev.mysql.com/doc/refman/5.7/en/json.html
+**
+** 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 <ctype.h>  /* amalgamator: keep */
+/* #include <stdlib.h> */
+/* #include <stdarg.h> */
+
+#define UNUSED_PARAM(X)  (void)(X)
+
+#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.
+*/
+#define safe_isdigit(x) isdigit((unsigned char)(x))
+#define safe_isalnum(x) isalnum((unsigned char)(x))
+
+/*
+** 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, 1, 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 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
+*/
+#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.iVal */
+#define JNODE_APPEND  0x10         /* More ARRAY/OBJECT entries at u.iAppend */
+#define JNODE_LABEL   0x20         /* Is a label of an object */
+
+
+/* A single node of parsed JSON
+*/
+struct JsonNode {
+  u8 eType;              /* One of the JSON_ type values */
+  u8 jnFlags;            /* JNODE flags */
+  u8 iVal;               /* Replacement value when JNODE_REPLACE */
+  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() */
+  } u;
+};
+
+/* 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 */
+};
+
+/**************************************************************************
+** Utility routines for dealing with JsonString objects
+**************************************************************************/
+
+/* 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;
+}
+
+/* Initialize the JsonString object
+*/
+static void jsonInit(JsonString *p, sqlite3_context *pCtx){
+  p->pCtx = pCtx;
+  p->bErr = 0;
+  jsonZero(p);
+}
+
+
+/* Free all allocated memory and reset the JsonString object back to its
+** initial state.
+*/
+static void jsonReset(JsonString *p){
+  if( !p->bStatic ) sqlite3_free(p->zBuf);
+  jsonZero(p);
+}
+
+
+/* Report an out-of-memory (OOM) condition 
+*/
+static void jsonOom(JsonString *p){
+  p->bErr = 1;
+  sqlite3_result_error_nomem(p->pCtx);
+  jsonReset(p);
+}
+
+/* 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;
+    }
+    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;
+}
+
+/* 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);
+}
+
+/* Append a single character
+*/
+static void jsonAppendChar(JsonString *p, char c){
+  if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return;
+  p->zBuf[p->nUsed++] = c;
+}
+
+/* Append a comma separator to the output buffer, if the previous
+** character is not '[' or '{'.
+*/
+static void jsonAppendSeparator(JsonString *p){
+  char c;
+  if( p->nUsed==0 ) return;
+  c = p->zBuf[p->nUsed-1];
+  if( c!='[' && c!='{' ) jsonAppendChar(p, ',');
+}
+
+/* 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 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++){
+    char c = zIn[i];
+    if( c=='"' || c=='\\' ){
+      if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return;
+      p->zBuf[p->nUsed++] = '\\';
+    }
+    p->zBuf[p->nUsed++] = c;
+  }
+  p->zBuf[p->nUsed++] = '"';
+  assert( p->nUsed<p->nAlloc );
+}
+
+/*
+** Append a function parameter value to the JSON string under 
+** construction.
+*/
+static void jsonAppendValue(
+  JsonString *p,                 /* Append to this JSON string */
+  sqlite3_value *pValue          /* Value to append */
+){
+  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 = 1;
+        jsonReset(p);
+      }
+      break;
+    }
+  }
+}
+
+
+/* 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);
+  }
+  assert( p->bStatic );
+}
+
+/**************************************************************************
+** Utility routines for dealing with JsonNode and JsonParse objects
+**************************************************************************/
+
+/*
+** 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 u32 jsonNodeSize(JsonNode *pNode){
+  return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1;
+}
+
+/*
+** Reclaim all memory allocated by a JsonParse object.  But do not
+** delete the JsonParse object itself.
+*/
+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;
+}
+
+/*
+** 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 */
+){
+  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;
+      }
+      /* 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|JNODE_REPLACE) ){
+            if( pNode[j].jnFlags & JNODE_REPLACE ){
+              jsonAppendSeparator(pOut);
+              jsonAppendValue(pOut, aReplace[pNode[j].iVal]);
+            }
+          }else{
+            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;
+      }
+      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, ':');
+            if( pNode[j+1].jnFlags & JNODE_REPLACE ){
+              jsonAppendValue(pOut, aReplace[pNode[j+1].iVal]);
+            }else{
+              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;
+      }
+      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);
+}
+
+/*
+** 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;
+            }
+          }
+        }
+        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 = strtod(pNode->u.zJContent, 0);
+      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<n-2; i++, k++){
+                c = z[i+1];
+                if( c>='0' && c<='9' ) v = v*16 + c - '0';
+                else if( c>='A' && c<='F' ) v = v*16 + c - 'A' + 10;
+                else if( c>='a' && c<='f' ) v = v*16 + c - 'a' + 10;
+                else break;
+              }
+              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*);
+
+/*
+** A macro to hint to the compiler that a function should not be
+** inlined.
+*/
+#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
+
+
+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);
+}
+
+/*
+** 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 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 */
+){
+  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->iVal = 0;
+  p->n = n;
+  p->u.zJContent = zContent;
+  return pParse->nNode++;
+}
+
+/*
+** 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 int jsonParseValue(JsonParse *pParse, u32 i){
+  char c;
+  u32 j;
+  int iThis;
+  int x;
+  JsonNode *pNode;
+  while( safe_isspace(pParse->zJson[i]) ){ i++; }
+  if( (c = pParse->zJson[i])=='{' ){
+    /* Parse object */
+    iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
+    if( iThis<0 ) return -1;
+    for(j=i+1;;j++){
+      while( safe_isspace(pParse->zJson[j]) ){ j++; }
+      x = jsonParseValue(pParse, j);
+      if( x<0 ){
+        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(pParse->zJson[j]) ){ j++; }
+      if( pParse->zJson[j]!=':' ) return -1;
+      j++;
+      x = jsonParseValue(pParse, j);
+      if( x<0 ) return -1;
+      j = x;
+      while( safe_isspace(pParse->zJson[j]) ){ j++; }
+      c = pParse->zJson[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(pParse->zJson[j]) ){ j++; }
+      x = jsonParseValue(pParse, j);
+      if( x<0 ){
+        if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1;
+        return -1;
+      }
+      j = x;
+      while( safe_isspace(pParse->zJson[j]) ){ j++; }
+      c = pParse->zJson[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 = pParse->zJson[j];
+      if( c==0 ) return -1;
+      if( c=='\\' ){
+        c = pParse->zJson[++j];
+        if( c==0 ) return -1;
+        jnFlags = JNODE_ESCAPE;
+      }else if( c=='"' ){
+        break;
+      }
+      j++;
+    }
+    jsonParseAddNode(pParse, JSON_STRING, j+1-i, &pParse->zJson[i]);
+    if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags;
+    return j+1;
+  }else if( c=='n'
+         && strncmp(pParse->zJson+i,"null",4)==0
+         && !safe_isalnum(pParse->zJson[i+4]) ){
+    jsonParseAddNode(pParse, JSON_NULL, 0, 0);
+    return i+4;
+  }else if( c=='t'
+         && strncmp(pParse->zJson+i,"true",4)==0
+         && !safe_isalnum(pParse->zJson[i+4]) ){
+    jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
+    return i+4;
+  }else if( c=='f'
+         && strncmp(pParse->zJson+i,"false",5)==0
+         && !safe_isalnum(pParse->zJson[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;
+    j = i+1;
+    for(;; j++){
+      c = pParse->zJson[j];
+      if( c>='0' && c<='9' ) continue;
+      if( c=='.' ){
+        if( pParse->zJson[j-1]=='-' ) return -1;
+        if( seenDP ) return -1;
+        seenDP = 1;
+        continue;
+      }
+      if( c=='e' || c=='E' ){
+        if( pParse->zJson[j-1]<'0' ) return -1;
+        if( seenE ) return -1;
+        seenDP = seenE = 1;
+        c = pParse->zJson[j+1];
+        if( c=='+' || c=='-' ){
+          j++;
+          c = pParse->zJson[j+1];
+        }
+        if( c<'0' || c>'9' ) return -1;
+        continue;
+      }
+      break;
+    }
+    if( pParse->zJson[j-1]<'0' ) return -1;
+    jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT,
+                        j - i, &pParse->zJson[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 */
+  }
+}
+
+/*
+** 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 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 ){
+    while( safe_isspace(zJson[i]) ) i++;
+    if( zJson[i] ) i = -1;
+  }
+  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 0;
+}
+
+/* Mark node i of pParse as being a child of iParent.  Call recursively
+** to fill in all the descendants of node i.
+*/
+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;
+    }
+  }
+}
+
+/*
+** Compute the parentage of all nodes in a completed parse.
+*/
+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;
+}
+
+/*
+** Compare the OBJECT label at pNode against zKey,nKey.  Return true on
+** a match.
+*/
+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;
+  }
+}
+
+/* forward declaration */
+static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**);
+
+/*
+** 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 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 */
+){
+  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;
+    }
+    if( nKey==0 ){
+      *pzErr = zPath;
+      return 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]);
+      }
+      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 0;
+}
+
+/*
+** Append content to pParse that will complete zPath.  Return a pointer
+** to the inserted node, or return NULL if the append fails.
+*/
+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 */
+){
+  *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;
+  }
+  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);
+}
+
+/*
+** 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.
+*/
+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 */
+){
+  const char *zErr = 0;
+  JsonNode *pNode = 0;
+  char *zMsg;
+
+  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;
+
+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;
+}
+
+
+/*
+** Report the wrong number of arguments for json_insert(), json_replace()
+** or json_set().
+*/
+static void jsonWrongNumArgs(
+  sqlite3_context *pCtx,
+  const char *zFuncName
+){
+  char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments",
+                               zFuncName);
+  sqlite3_result_error(pCtx, zMsg, -1);
+  sqlite3_free(zMsg);     
+}
+
+
+/****************************************************************************
+** SQL functions used for testing and debugging
+****************************************************************************/
+
+#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;
+
+  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{
+      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);
+}
+
+/*
+** 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 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 */
+
+/****************************************************************************
+** SQL function implementations
+****************************************************************************/
+
+/*
+** 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 void jsonArrayFunc(
+  sqlite3_context *ctx,
+  int argc,
+  sqlite3_value **argv
+){
+  int i;
+  JsonString jx;
+
+  jsonInit(&jx, ctx);
+  jsonAppendChar(&jx, '[');
+  for(i=0; i<argc; i++){
+    jsonAppendSeparator(&jx);
+    jsonAppendValue(&jx, argv[i]);
+  }
+  jsonAppendChar(&jx, ']');
+  jsonResult(&jx);
+  sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+}
+
+
+/*
+** 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 void jsonArrayLengthFunc(
+  sqlite3_context *ctx,
+  int argc,
+  sqlite3_value **argv
+){
+  JsonParse x;          /* The parse */
+  sqlite3_int64 n = 0;
+  u32 i;
+  JsonNode *pNode;
+
+  if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
+  assert( x.nNode );
+  if( argc==2 ){
+    const char *zPath = (const char*)sqlite3_value_text(argv[1]);
+    pNode = jsonLookup(&x, zPath, 0, ctx);
+  }else{
+    pNode = x.aNode;
+  }
+  if( pNode==0 ){
+    x.nErr = 1;
+  }else if( pNode->eType==JSON_ARRAY ){
+    assert( (pNode->jnFlags & JNODE_APPEND)==0 );
+    for(i=1; i<=pNode->n; n++){
+      i += jsonNodeSize(&pNode[i]);
+    }
+  }
+  if( x.nErr==0 ) sqlite3_result_int64(ctx, n);
+  jsonParseReset(&x);
+}
+
+/*
+** 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 jsonExtractFunc(
+  sqlite3_context *ctx,
+  int argc,
+  sqlite3_value **argv
+){
+  JsonParse x;          /* The parse */
+  JsonNode *pNode;
+  const char *zPath;
+  JsonString jx;
+  int i;
+
+  if( argc<2 ) return;
+  if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
+  jsonInit(&jx, ctx);
+  jsonAppendChar(&jx, '[');
+  for(i=1; i<argc; i++){
+    zPath = (const char*)sqlite3_value_text(argv[i]);
+    pNode = jsonLookup(&x, zPath, 0, ctx);
+    if( x.nErr ) break;
+    if( argc>2 ){
+      jsonAppendSeparator(&jx);
+      if( pNode ){
+        jsonRenderNode(pNode, &jx, 0);
+      }else{
+        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);
+  jsonParseReset(&x);
+}
+
+/*
+** 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;
+
+  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);
+}
+
+
+/*
+** 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;
+
+  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);
+}
+
+/*
+** 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;
+
+  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->iVal = (u8)(i+1);
+    }
+  }
+  if( x.aNode[0].jnFlags & JNODE_REPLACE ){
+    sqlite3_result_value(ctx, argv[x.aNode[0].iVal]);
+  }else{
+    jsonReturnJson(x.aNode, ctx, argv);
+  }
+replace_err:
+  jsonParseReset(&x);
+}
+
+/*
+** 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 void jsonSetFunc(
+  sqlite3_context *ctx,
+  int argc,
+  sqlite3_value **argv
+){
+  JsonParse x;          /* The parse */
+  JsonNode *pNode;
+  const char *zPath;
+  u32 i;
+  int bApnd;
+  int bIsSet = *(int*)sqlite3_user_data(ctx);
+
+  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->iVal = (u8)(i+1);
+    }
+  }
+  if( x.aNode[0].jnFlags & JNODE_REPLACE ){
+    sqlite3_result_value(ctx, argv[x.aNode[0].iVal]);
+  }else{
+    jsonReturnJson(x.aNode, ctx, argv);
+  }
+jsonSetDone:
+  jsonParseReset(&x);
+}
+
+/*
+** 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.
+*/
+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);
+  }else{
+    pNode = x.aNode;
+  }
+  if( pNode ){
+    sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC);
+  }
+  jsonParseReset(&x);
+}
+
+/*
+** json_valid(JSON)
+**
+** Return 1 if JSON is a well-formed JSON string according to RFC-7159.
+** Return 0 otherwise.
+*/
+static void jsonValidFunc(
+  sqlite3_context *ctx,
+  int argc,
+  sqlite3_value **argv
+){
+  JsonParse x;          /* The parse */
+  int rc = 0;
+
+  UNUSED_PARAM(argc);
+  if( jsonParse(&x, 0, (const char*)sqlite3_value_text(argv[0]))==0 ){
+    rc = 1;
+  }
+  jsonParseReset(&x);
+  sqlite3_result_int(ctx, rc);
+}
+
+#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
+){
+  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
+
+  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));
+  }
+  return rc;
+}
+
+/* destructor for json_each virtual table */
+static int jsonEachDisconnect(sqlite3_vtab *pVtab){
+  sqlite3_free(pVtab);
+  return SQLITE_OK;
+}
+
+/* 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;
+}
+
+/* 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;
+}
+
+/* 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;
+}
+
+/* Destructor for a jsonEachCursor object */
+static int jsonEachClose(sqlite3_vtab_cursor *cur){
+  JsonEachCursor *p = (JsonEachCursor*)cur;
+  jsonEachCursorReset(p);
+  sqlite3_free(cur);
+  return SQLITE_OK;
+}
+
+/* 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;
+}
+
+/* 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;
+      }
+    }
+  }
+  return SQLITE_OK;
+}
+
+/* Append the name of the path for element i to pStr
+*/
+static void jsonEachComputePath(
+  JsonEachCursor *p,       /* The cursor */
+  JsonString *pStr,        /* Write the path here */
+  u32 i                    /* Path to this element */
+){
+  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);
+  }
+}
+
+/* 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{
+          iKey = p->iRowid;
+        }
+        sqlite3_result_int64(ctx, (sqlite3_int64)iKey);
+      }
+      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;
+    }
+    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{
+          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 */
+    }
+    case JEACH_ROOT: {
+      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;
+    }
+  }
+  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;
+}
+
+/* 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 jsonIdx = -1;
+  int rootIdx = -1;
+  const struct sqlite3_index_constraint *pConstraint;
+
+  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;
+  }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;
+    }
+  }
+  return SQLITE_OK;
+}
+
+/* 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;
+
+  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;
+    }
+  }
+  return SQLITE_OK;
+}
+
+/* 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 */
+};
+
+/* 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 */
+
+/****************************************************************************
+** The following routines are the only publically visible identifiers in this
+** file.  Call the following routines in order to register the various SQL
+** functions and the virtual table implemented by this file.
+****************************************************************************/
+
+SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){
+  int rc = SQLITE_OK;
+  unsigned int i;
+  static const struct {
+     const char *zName;
+     int nArg;
+     int flag;
+     void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
+  } aFunc[] = {
+    { "json",                 1, 0,   jsonRemoveFunc        },
+    { "json_array",          -1, 0,   jsonArrayFunc         },
+    { "json_array_length",    1, 0,   jsonArrayLengthFunc   },
+    { "json_array_length",    2, 0,   jsonArrayLengthFunc   },
+    { "json_extract",        -1, 0,   jsonExtractFunc       },
+    { "json_insert",         -1, 0,   jsonSetFunc           },
+    { "json_object",         -1, 0,   jsonObjectFunc        },
+    { "json_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         },
+
+#if SQLITE_DEBUG
+    /* DEBUG and TESTING functions */
+    { "json_parse",           1, 0,   jsonParseFunc         },
+    { "json_test1",           1, 0,   jsonTest1Func         },
+#endif
+  };
+#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);
+  }
+#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;
+}
+
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+SQLITE_API int SQLITE_STDCALL sqlite3_json_init(
+  sqlite3 *db, 
+  char **pzErrMsg, 
+  const sqlite3_api_routines *pApi
+){
+  SQLITE_EXTENSION_INIT2(pApi);
+  (void)pzErrMsg;  /* Unused parameter */
+  return sqlite3Json1Init(db);
+}
+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1) */
+
+/************** End of json1.c ***********************************************/
+/************** Begin file fts5.c ********************************************/
+
+
+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) 
+
+#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) 
+# define NDEBUG 1
+#endif
+#if defined(NDEBUG) && defined(SQLITE_DEBUG)
+# undef NDEBUG
+#endif
+
+/*
+** 2014 May 31
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** Interfaces to extend FTS5. Using the interfaces defined in this file, 
+** FTS5 may be extended with:
+**
+**     * custom tokenizers, and
+**     * custom auxiliary functions.
+*/
+
+
+#ifndef _FTS5_H
+#define _FTS5_H
+
+/* #include "sqlite3.h" */
+
+#if 0
+extern "C" {
+#endif
+
+/*************************************************************************
+** CUSTOM AUXILIARY FUNCTIONS
+**
+** Virtual table implementations may overload SQL functions by implementing
+** the sqlite3_module.xFindFunction() method.
+*/
+
+typedef struct Fts5ExtensionApi Fts5ExtensionApi;
+typedef struct Fts5Context Fts5Context;
+typedef struct Fts5PhraseIter Fts5PhraseIter;
+
+typedef void (*fts5_extension_function)(
+  const Fts5ExtensionApi *pApi,   /* API offered by current FTS version */
+  Fts5Context *pFts,              /* First arg to pass to pApi functions */
+  sqlite3_context *pCtx,          /* Context for returning result/error */
+  int nVal,                       /* Number of values in apVal[] array */
+  sqlite3_value **apVal           /* Array of trailing arguments */
+);
+
+struct Fts5PhraseIter {
+  const unsigned char *a;
+  const unsigned char *b;
+};
+
+/*
+** EXTENSION API FUNCTIONS
+**
+** xUserData(pFts):
+**   Return a copy of the context pointer the extension function was 
+**   registered with.
+**
+** xColumnTotalSize(pFts, iCol, pnToken):
+**   If parameter iCol is less than zero, set output variable *pnToken
+**   to the total number of tokens in the FTS5 table. Or, if iCol is
+**   non-negative but less than the number of columns in the table, return
+**   the total number of tokens in column iCol, considering all rows in 
+**   the FTS5 table.
+**
+**   If parameter iCol is greater than or equal to the number of columns
+**   in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
+**   an OOM condition or IO error), an appropriate SQLite error code is 
+**   returned.
+**
+** xColumnCount(pFts):
+**   Return the number of columns in the table.
+**
+** xColumnSize(pFts, iCol, pnToken):
+**   If parameter iCol is less than zero, set output variable *pnToken
+**   to the total number of tokens in the current row. Or, if iCol is
+**   non-negative but less than the number of columns in the table, set
+**   *pnToken to the number of tokens in column iCol of the current row.
+**
+**   If parameter iCol is greater than or equal to the number of columns
+**   in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
+**   an OOM condition or IO error), an appropriate SQLite error code is 
+**   returned.
+**
+** xColumnText:
+**   This function attempts to retrieve the text of column iCol of the
+**   current document. If successful, (*pz) is set to point to a buffer
+**   containing the text in utf-8 encoding, (*pn) is set to the size in bytes
+**   (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
+**   if an error occurs, an SQLite error code is returned and the final values
+**   of (*pz) and (*pn) are undefined.
+**
+** xPhraseCount:
+**   Returns the number of phrases in the current query expression.
+**
+** xPhraseSize:
+**   Returns the number of tokens in phrase iPhrase of the query. Phrases
+**   are numbered starting from zero.
+**
+** xInstCount:
+**   Set *pnInst to the total number of occurrences of all phrases within
+**   the query within the current row. Return SQLITE_OK if successful, or
+**   an error code (i.e. SQLITE_NOMEM) if an error occurs.
+**
+** xInst:
+**   Query for the details of phrase match iIdx within the current row.
+**   Phrase matches are numbered starting from zero, so the iIdx argument
+**   should be greater than or equal to zero and smaller than the value
+**   output by xInstCount().
+**
+**   Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) 
+**   if an error occurs.
+**
+** xRowid:
+**   Returns the rowid of the current row.
+**
+** xTokenize:
+**   Tokenize text using the tokenizer belonging to the FTS5 table.
+**
+** xQueryPhrase(pFts5, iPhrase, pUserData, xCallback):
+**   This API function is used to query the FTS table for phrase iPhrase
+**   of the current query. Specifically, a query equivalent to:
+**
+**       ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid
+**
+**   with $p set to a phrase equivalent to the phrase iPhrase of the
+**   current query is executed. For each row visited, the callback function
+**   passed as the fourth argument is invoked. The context and API objects 
+**   passed to the callback function may be used to access the properties of
+**   each matched row. Invoking Api.xUserData() returns a copy of the pointer
+**   passed as the third argument to pUserData.
+**
+**   If the callback function returns any value other than SQLITE_OK, the
+**   query is abandoned and the xQueryPhrase function returns immediately.
+**   If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK.
+**   Otherwise, the error code is propagated upwards.
+**
+**   If the query runs to completion without incident, SQLITE_OK is returned.
+**   Or, if some error occurs before the query completes or is aborted by
+**   the callback, an SQLite error code is returned.
+**
+**
+** xSetAuxdata(pFts5, pAux, xDelete)
+**
+**   Save the pointer passed as the second argument as the extension functions 
+**   "auxiliary data". The pointer may then be retrieved by the current or any
+**   future invocation of the same fts5 extension function made as part of
+**   of the same MATCH query using the xGetAuxdata() API.
+**
+**   Each extension function is allocated a single auxiliary data slot for
+**   each FTS query (MATCH expression). If the extension function is invoked 
+**   more than once for a single FTS query, then all invocations share a 
+**   single auxiliary data context.
+**
+**   If there is already an auxiliary data pointer when this function is
+**   invoked, then it is replaced by the new pointer. If an xDelete callback
+**   was specified along with the original pointer, it is invoked at this
+**   point.
+**
+**   The xDelete callback, if one is specified, is also invoked on the
+**   auxiliary data pointer after the FTS5 query has finished.
+**
+**   If an error (e.g. an OOM condition) occurs within this function, an
+**   the auxiliary data is set to NULL and an error code returned. If the
+**   xDelete parameter was not NULL, it is invoked on the auxiliary data
+**   pointer before returning.
+**
+**
+** xGetAuxdata(pFts5, bClear)
+**
+**   Returns the current auxiliary data pointer for the fts5 extension 
+**   function. See the xSetAuxdata() method for details.
+**
+**   If the bClear argument is non-zero, then the auxiliary data is cleared
+**   (set to NULL) before this function returns. In this case the xDelete,
+**   if any, is not invoked.
+**
+**
+** xRowCount(pFts5, pnRow)
+**
+**   This function is used to retrieve the total number of rows in the table.
+**   In other words, the same value that would be returned by:
+**
+**        SELECT count(*) FROM ftstable;
+**
+** xPhraseFirst()
+**   This function is used, along with type Fts5PhraseIter and the xPhraseNext
+**   method, to iterate through all instances of a single query phrase within
+**   the current row. This is the same information as is accessible via the
+**   xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient
+**   to use, this API may be faster under some circumstances. To iterate 
+**   through instances of phrase iPhrase, use the following code:
+**
+**       Fts5PhraseIter iter;
+**       int iCol, iOff;
+**       for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
+**           iOff>=0;
+**           pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
+**       ){
+**         // An instance of phrase iPhrase at offset iOff of column iCol
+**       }
+**
+**   The Fts5PhraseIter structure is defined above. Applications should not
+**   modify this structure directly - it should only be used as shown above
+**   with the xPhraseFirst() and xPhraseNext() API methods.
+**
+** xPhraseNext()
+**   See xPhraseFirst above.
+*/
+struct Fts5ExtensionApi {
+  int iVersion;                   /* Currently always set to 1 */
+
+  void *(*xUserData)(Fts5Context*);
+
+  int (*xColumnCount)(Fts5Context*);
+  int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
+  int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken);
+
+  int (*xTokenize)(Fts5Context*, 
+    const char *pText, int nText, /* Text to tokenize */
+    void *pCtx,                   /* Context passed to xToken() */
+    int (*xToken)(void*, int, const char*, int, int, int)       /* Callback */
+  );
+
+  int (*xPhraseCount)(Fts5Context*);
+  int (*xPhraseSize)(Fts5Context*, int iPhrase);
+
+  int (*xInstCount)(Fts5Context*, int *pnInst);
+  int (*xInst)(Fts5Context*, int iIdx, int *piPhrase, int *piCol, int *piOff);
+
+  sqlite3_int64 (*xRowid)(Fts5Context*);
+  int (*xColumnText)(Fts5Context*, int iCol, const char **pz, int *pn);
+  int (*xColumnSize)(Fts5Context*, int iCol, int *pnToken);
+
+  int (*xQueryPhrase)(Fts5Context*, int iPhrase, void *pUserData,
+    int(*)(const Fts5ExtensionApi*,Fts5Context*,void*)
+  );
+  int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
+  void *(*xGetAuxdata)(Fts5Context*, int bClear);
+
+  void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
+  void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
+};
+
+/* 
+** CUSTOM AUXILIARY FUNCTIONS
+*************************************************************************/
+
+/*************************************************************************
+** CUSTOM TOKENIZERS
+**
+** Applications may also register custom tokenizer types. A tokenizer 
+** is registered by providing fts5 with a populated instance of the 
+** following structure. All structure methods must be defined, setting
+** any member of the fts5_tokenizer struct to NULL leads to undefined
+** behaviour. The structure methods are expected to function as follows:
+**
+** xCreate:
+**   This function is used to allocate and inititalize a tokenizer instance.
+**   A tokenizer instance is required to actually tokenize text.
+**
+**   The first argument passed to this function is a copy of the (void*)
+**   pointer provided by the application when the fts5_tokenizer object
+**   was registered with FTS5 (the third argument to xCreateTokenizer()). 
+**   The second and third arguments are an array of nul-terminated strings
+**   containing the tokenizer arguments, if any, specified following the
+**   tokenizer name as part of the CREATE VIRTUAL TABLE statement used
+**   to create the FTS5 table.
+**
+**   The final argument is an output variable. If successful, (*ppOut) 
+**   should be set to point to the new tokenizer handle and SQLITE_OK
+**   returned. If an error occurs, some value other than SQLITE_OK should
+**   be returned. In this case, fts5 assumes that the final value of *ppOut 
+**   is undefined.
+**
+** xDelete:
+**   This function is invoked to delete a tokenizer handle previously
+**   allocated using xCreate(). Fts5 guarantees that this function will
+**   be invoked exactly once for each successful call to xCreate().
+**
+** xTokenize:
+**   This function is expected to tokenize the nText byte string indicated 
+**   by argument pText. pText may or may not be nul-terminated. The first
+**   argument passed to this function is a pointer to an Fts5Tokenizer object
+**   returned by an earlier call to xCreate().
+**
+**   The second argument indicates the reason that FTS5 is requesting
+**   tokenization of the supplied text. This is always one of the following
+**   four values:
+**
+**   <ul><li> <b>FTS5_TOKENIZE_DOCUMENT</b> - A document is being inserted into
+**            or removed from the FTS table. The tokenizer is being invoked to
+**            determine the set of tokens to add to (or delete from) the
+**            FTS index.
+**
+**       <li> <b>FTS5_TOKENIZE_QUERY</b> - A MATCH query is being executed 
+**            against the FTS index. The tokenizer is being called to tokenize 
+**            a bareword or quoted string specified as part of the query.
+**
+**       <li> <b>(FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX)</b> - Same as
+**            FTS5_TOKENIZE_QUERY, except that the bareword or quoted string is
+**            followed by a "*" character, indicating that the last token
+**            returned by the tokenizer will be treated as a token prefix.
+**
+**       <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to 
+**            satisfy an fts5_api.xTokenize() request made by an auxiliary
+**            function. Or an fts5_api.xColumnSize() request made by the same
+**            on a columnsize=0 database.  
+**   </ul>
+**
+**   For each token in the input string, the supplied callback xToken() must
+**   be invoked. The first argument to it should be a copy of the pointer
+**   passed as the second argument to xTokenize(). The third and fourth
+**   arguments are a pointer to a buffer containing the token text, and the
+**   size of the token in bytes. The 4th and 5th arguments are the byte offsets
+**   of the first byte of and first byte immediately following the text from
+**   which the token is derived within the input.
+**
+**   The second argument passed to the xToken() callback ("tflags") should
+**   normally be set to 0. The exception is if the tokenizer supports 
+**   synonyms. In this case see the discussion below for details.
+**
+**   FTS5 assumes the xToken() callback is invoked for each token in the 
+**   order that they occur within the input text.
+**
+**   If an xToken() callback returns any value other than SQLITE_OK, then
+**   the tokenization should be abandoned and the xTokenize() method should
+**   immediately return a copy of the xToken() return value. Or, if the
+**   input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally,
+**   if an error occurs with the xTokenize() implementation itself, it
+**   may abandon the tokenization and return any error code other than
+**   SQLITE_OK or SQLITE_DONE.
+**
+** SYNONYM SUPPORT
+**
+**   Custom tokenizers may also support synonyms. Consider a case in which a
+**   user wishes to query for a phrase such as "first place". Using the 
+**   built-in tokenizers, the FTS5 query 'first + place' will match instances
+**   of "first place" within the document set, but not alternative forms
+**   such as "1st place". In some applications, it would be better to match
+**   all instances of "first place" or "1st place" regardless of which form
+**   the user specified in the MATCH query text.
+**
+**   There are several ways to approach this in FTS5:
+**
+**   <ol><li> By mapping all synonyms to a single token. In this case, the 
+**            In the above example, this means that the tokenizer returns the
+**            same token for inputs "first" and "1st". Say that token is in
+**            fact "first", so that when the user inserts the document "I won
+**            1st place" entries are added to the index for tokens "i", "won",
+**            "first" and "place". If the user then queries for '1st + place',
+**            the tokenizer substitutes "first" for "1st" and the query works
+**            as expected.
+**
+**       <li> By adding multiple synonyms for a single term to the FTS index.
+**            In this case, when tokenizing query text, the tokenizer may 
+**            provide multiple synonyms for a single term within the document.
+**            FTS5 then queries the index for each synonym individually. For
+**            example, faced with the query:
+**
+**   <codeblock>
+**     ... MATCH 'first place'</codeblock>
+**
+**            the tokenizer offers both "1st" and "first" as synonyms for the
+**            first token in the MATCH query and FTS5 effectively runs a query 
+**            similar to:
+**
+**   <codeblock>
+**     ... MATCH '(first OR 1st) place'</codeblock>
+**
+**            except that, for the purposes of auxiliary functions, the query
+**            still appears to contain just two phrases - "(first OR 1st)" 
+**            being treated as a single phrase.
+**
+**       <li> By adding multiple synonyms for a single term to the FTS index.
+**            Using this method, when tokenizing document text, the tokenizer
+**            provides multiple synonyms for each token. So that when a 
+**            document such as "I won first place" is tokenized, entries are
+**            added to the FTS index for "i", "won", "first", "1st" and
+**            "place".
+**
+**            This way, even if the tokenizer does not provide synonyms
+**            when tokenizing query text (it should not - to do would be
+**            inefficient), it doesn't matter if the user queries for 
+**            'first + place' or '1st + place', as there are entires in the
+**            FTS index corresponding to both forms of the first token.
+**   </ol>
+**
+**   Whether it is parsing document or query text, any call to xToken that
+**   specifies a <i>tflags</i> argument with the FTS5_TOKEN_COLOCATED bit
+**   is considered to supply a synonym for the previous token. For example,
+**   when parsing the document "I won first place", a tokenizer that supports
+**   synonyms would call xToken() 5 times, as follows:
+**
+**   <codeblock>
+**       xToken(pCtx, 0, "i",                      1,  0,  1);
+**       xToken(pCtx, 0, "won",                    3,  2,  5);
+**       xToken(pCtx, 0, "first",                  5,  6, 11);
+**       xToken(pCtx, FTS5_TOKEN_COLOCATED, "1st", 3,  6, 11);
+**       xToken(pCtx, 0, "place",                  5, 12, 17);
+**</codeblock>
+**
+**   It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time
+**   xToken() is called. Multiple synonyms may be specified for a single token
+**   by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence. 
+**   There is no limit to the number of synonyms that may be provided for a
+**   single token.
+**
+**   In many cases, method (1) above is the best approach. It does not add 
+**   extra data to the FTS index or require FTS5 to query for multiple terms,
+**   so it is efficient in terms of disk space and query speed. However, it
+**   does not support prefix queries very well. If, as suggested above, the
+**   token "first" is subsituted for "1st" by the tokenizer, then the query:
+**
+**   <codeblock>
+**     ... MATCH '1s*'</codeblock>
+**
+**   will not match documents that contain the token "1st" (as the tokenizer
+**   will probably not map "1s" to any prefix of "first").
+**
+**   For full prefix support, method (3) may be preferred. In this case, 
+**   because the index contains entries for both "first" and "1st", prefix
+**   queries such as 'fi*' or '1s*' will match correctly. However, because
+**   extra entries are added to the FTS index, this method uses more space
+**   within the database.
+**
+**   Method (2) offers a midpoint between (1) and (3). Using this method,
+**   a query such as '1s*' will match documents that contain the literal 
+**   token "1st", but not "first" (assuming the tokenizer is not able to
+**   provide synonyms for prefixes). However, a non-prefix query like '1st'
+**   will match against "1st" and "first". This method does not require
+**   extra disk space, as no extra entries are added to the FTS index. 
+**   On the other hand, it may require more CPU cycles to run MATCH queries,
+**   as separate queries of the FTS index are required for each synonym.
+**
+**   When using methods (2) or (3), it is important that the tokenizer only
+**   provide synonyms when tokenizing document text (method (2)) or query
+**   text (method (3)), not both. Doing so will not cause any errors, but is
+**   inefficient.
+*/
+typedef struct Fts5Tokenizer Fts5Tokenizer;
+typedef struct fts5_tokenizer fts5_tokenizer;
+struct fts5_tokenizer {
+  int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
+  void (*xDelete)(Fts5Tokenizer*);
+  int (*xTokenize)(Fts5Tokenizer*, 
+      void *pCtx,
+      int flags,            /* Mask of FTS5_TOKENIZE_* flags */
+      const char *pText, int nText, 
+      int (*xToken)(
+        void *pCtx,         /* Copy of 2nd argument to xTokenize() */
+        int tflags,         /* Mask of FTS5_TOKEN_* flags */
+        const char *pToken, /* Pointer to buffer containing token */
+        int nToken,         /* Size of token in bytes */
+        int iStart,         /* Byte offset of token within input text */
+        int iEnd            /* Byte offset of end of token within input text */
+      )
+  );
+};
+
+/* Flags that may be passed as the third argument to xTokenize() */
+#define FTS5_TOKENIZE_QUERY     0x0001
+#define FTS5_TOKENIZE_PREFIX    0x0002
+#define FTS5_TOKENIZE_DOCUMENT  0x0004
+#define FTS5_TOKENIZE_AUX       0x0008
+
+/* Flags that may be passed by the tokenizer implementation back to FTS5
+** as the third argument to the supplied xToken callback. */
+#define FTS5_TOKEN_COLOCATED    0x0001      /* Same position as prev. token */
+
+/*
+** END OF CUSTOM TOKENIZERS
+*************************************************************************/
+
+/*************************************************************************
+** FTS5 EXTENSION REGISTRATION API
+*/
+typedef struct fts5_api fts5_api;
+struct fts5_api {
+  int iVersion;                   /* Currently always set to 2 */
+
+  /* Create a new tokenizer */
+  int (*xCreateTokenizer)(
+    fts5_api *pApi,
+    const char *zName,
+    void *pContext,
+    fts5_tokenizer *pTokenizer,
+    void (*xDestroy)(void*)
+  );
+
+  /* Find an existing tokenizer */
+  int (*xFindTokenizer)(
+    fts5_api *pApi,
+    const char *zName,
+    void **ppContext,
+    fts5_tokenizer *pTokenizer
+  );
+
+  /* Create a new auxiliary function */
+  int (*xCreateFunction)(
+    fts5_api *pApi,
+    const char *zName,
+    void *pContext,
+    fts5_extension_function xFunction,
+    void (*xDestroy)(void*)
+  );
+};
+
+/*
+** END OF REGISTRATION API
+*************************************************************************/
+
+#if 0
+}  /* end of the 'extern "C"' block */
+#endif
+
+#endif /* _FTS5_H */
+
+
+/*
+** 2014 May 31
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+*/
+#ifndef _FTS5INT_H
+#define _FTS5INT_H
+
+/* #include "sqlite3ext.h" */
+SQLITE_EXTENSION_INIT1
+
+/* #include <string.h> */
+/* #include <assert.h> */
+
+#ifndef SQLITE_AMALGAMATION
+
+typedef unsigned char  u8;
+typedef unsigned int   u32;
+typedef unsigned short u16;
+typedef sqlite3_int64 i64;
+typedef sqlite3_uint64 u64;
+
+#define ArraySize(x) (sizeof(x) / sizeof(x[0]))
+
+#define testcase(x)
+#define ALWAYS(x) 1
+#define NEVER(x) 0
+
+#define MIN(x,y) (((x) < (y)) ? (x) : (y))
+#define MAX(x,y) (((x) > (y)) ? (x) : (y))
+
+/*
+** Constants for the largest and smallest possible 64-bit signed integers.
+*/
+# define LARGEST_INT64  (0xffffffff|(((i64)0x7fffffff)<<32))
+# define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
+
+#endif
+
+
+/*
+** Maximum number of prefix indexes on single FTS5 table. This must be
+** less than 32. If it is set to anything large than that, an #error
+** directive in fts5_index.c will cause the build to fail.
+*/
+#define FTS5_MAX_PREFIX_INDEXES 31
+
+#define FTS5_DEFAULT_NEARDIST 10
+#define FTS5_DEFAULT_RANK     "bm25"
+
+/* Name of rank and rowid columns */
+#define FTS5_RANK_NAME "rank"
+#define FTS5_ROWID_NAME "rowid"
+
+#ifdef SQLITE_DEBUG
+# define FTS5_CORRUPT sqlite3Fts5Corrupt()
+static int sqlite3Fts5Corrupt(void);
+#else
+# define FTS5_CORRUPT SQLITE_CORRUPT_VTAB
+#endif
+
+/*
+** The assert_nc() macro is similar to the assert() macro, except that it
+** is used for assert() conditions that are true only if it can be 
+** guranteed that the database is not corrupt.
+*/
+#ifdef SQLITE_DEBUG
+SQLITE_API extern int sqlite3_fts5_may_be_corrupt;
+# define assert_nc(x) assert(sqlite3_fts5_may_be_corrupt || (x))
+#else
+# define assert_nc(x) assert(x)
+#endif
+
+typedef struct Fts5Global Fts5Global;
+typedef struct Fts5Colset Fts5Colset;
+
+/* If a NEAR() clump or phrase may only match a specific set of columns, 
+** then an object of the following type is used to record the set of columns.
+** Each entry in the aiCol[] array is a column that may be matched.
+**
+** This object is used by fts5_expr.c and fts5_index.c.
+*/
+struct Fts5Colset {
+  int nCol;
+  int aiCol[1];
+};
+
+
+
+/**************************************************************************
+** Interface to code in fts5_config.c. fts5_config.c contains contains code
+** to parse the arguments passed to the CREATE VIRTUAL TABLE statement.
+*/
+
+typedef struct Fts5Config Fts5Config;
+
+/*
+** An instance of the following structure encodes all information that can
+** be gleaned from the CREATE VIRTUAL TABLE statement.
+**
+** And all information loaded from the %_config table.
+**
+** nAutomerge:
+**   The minimum number of segments that an auto-merge operation should
+**   attempt to merge together. A value of 1 sets the object to use the 
+**   compile time default. Zero disables auto-merge altogether.
+**
+** zContent:
+**
+** zContentRowid:
+**   The value of the content_rowid= option, if one was specified. Or 
+**   the string "rowid" otherwise. This text is not quoted - if it is
+**   used as part of an SQL statement it needs to be quoted appropriately.
+**
+** zContentExprlist:
+**
+** pzErrmsg:
+**   This exists in order to allow the fts5_index.c module to return a 
+**   decent error message if it encounters a file-format version it does
+**   not understand.
+**
+** bColumnsize:
+**   True if the %_docsize table is created.
+**
+** bPrefixIndex:
+**   This is only used for debugging. If set to false, any prefix indexes
+**   are ignored. This value is configured using:
+**
+**       INSERT INTO tbl(tbl, rank) VALUES('prefix-index', $bPrefixIndex);
+**
+*/
+struct Fts5Config {
+  sqlite3 *db;                    /* Database handle */
+  char *zDb;                      /* Database holding FTS index (e.g. "main") */
+  char *zName;                    /* Name of FTS index */
+  int nCol;                       /* Number of columns */
+  char **azCol;                   /* Column names */
+  u8 *abUnindexed;                /* True for unindexed columns */
+  int nPrefix;                    /* Number of prefix indexes */
+  int *aPrefix;                   /* Sizes in bytes of nPrefix prefix indexes */
+  int eContent;                   /* An FTS5_CONTENT value */
+  char *zContent;                 /* content table */ 
+  char *zContentRowid;            /* "content_rowid=" option value */ 
+  int bColumnsize;                /* "columnsize=" option value (dflt==1) */
+  char *zContentExprlist;
+  Fts5Tokenizer *pTok;
+  fts5_tokenizer *pTokApi;
+
+  /* Values loaded from the %_config table */
+  int iCookie;                    /* Incremented when %_config is modified */
+  int pgsz;                       /* Approximate page size used in %_data */
+  int nAutomerge;                 /* 'automerge' setting */
+  int nCrisisMerge;               /* Maximum allowed segments per level */
+  char *zRank;                    /* Name of rank function */
+  char *zRankArgs;                /* Arguments to rank function */
+
+  /* If non-NULL, points to sqlite3_vtab.base.zErrmsg. Often NULL. */
+  char **pzErrmsg;
+
+#ifdef SQLITE_DEBUG
+  int bPrefixIndex;               /* True to use prefix-indexes */
+#endif
+};
+
+/* Current expected value of %_config table 'version' field */
+#define FTS5_CURRENT_VERSION 4
+
+#define FTS5_CONTENT_NORMAL   0
+#define FTS5_CONTENT_NONE     1
+#define FTS5_CONTENT_EXTERNAL 2
+
+
+
+
+static int sqlite3Fts5ConfigParse(
+    Fts5Global*, sqlite3*, int, const char **, Fts5Config**, char**
+);
+static void sqlite3Fts5ConfigFree(Fts5Config*);
+
+static int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig);
+
+static int sqlite3Fts5Tokenize(
+  Fts5Config *pConfig,            /* FTS5 Configuration object */
+  int flags,                      /* FTS5_TOKENIZE_* flags */
+  const char *pText, int nText,   /* Text to tokenize */
+  void *pCtx,                     /* Context passed to xToken() */
+  int (*xToken)(void*, int, const char*, int, int, int)    /* Callback */
+);
+
+static void sqlite3Fts5Dequote(char *z);
+
+/* Load the contents of the %_config table */
+static int sqlite3Fts5ConfigLoad(Fts5Config*, int);
+
+/* Set the value of a single config attribute */
+static int sqlite3Fts5ConfigSetValue(Fts5Config*, const char*, sqlite3_value*, int*);
+
+static int sqlite3Fts5ConfigParseRank(const char*, char**, char**);
+
+/*
+** End of interface to code in fts5_config.c.
+**************************************************************************/
+
+/**************************************************************************
+** Interface to code in fts5_buffer.c.
+*/
+
+/*
+** Buffer object for the incremental building of string data.
+*/
+typedef struct Fts5Buffer Fts5Buffer;
+struct Fts5Buffer {
+  u8 *p;
+  int n;
+  int nSpace;
+};
+
+static int sqlite3Fts5BufferGrow(int*, Fts5Buffer*, int);
+static void sqlite3Fts5BufferAppendVarint(int*, Fts5Buffer*, i64);
+static void sqlite3Fts5BufferAppendBlob(int*, Fts5Buffer*, int, const u8*);
+static void sqlite3Fts5BufferAppendString(int *, Fts5Buffer*, const char*);
+static void sqlite3Fts5BufferFree(Fts5Buffer*);
+static void sqlite3Fts5BufferZero(Fts5Buffer*);
+static void sqlite3Fts5BufferSet(int*, Fts5Buffer*, int, const u8*);
+static void sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, char *zFmt, ...);
+static void sqlite3Fts5BufferAppend32(int*, Fts5Buffer*, int);
+
+static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...);
+
+#define fts5BufferZero(x)             sqlite3Fts5BufferZero(x)
+#define fts5BufferGrow(a,b,c)         sqlite3Fts5BufferGrow(a,b,c)
+#define fts5BufferAppendVarint(a,b,c) sqlite3Fts5BufferAppendVarint(a,b,c)
+#define fts5BufferFree(a)             sqlite3Fts5BufferFree(a)
+#define fts5BufferAppendBlob(a,b,c,d) sqlite3Fts5BufferAppendBlob(a,b,c,d)
+#define fts5BufferSet(a,b,c,d)        sqlite3Fts5BufferSet(a,b,c,d)
+#define fts5BufferAppend32(a,b,c)     sqlite3Fts5BufferAppend32(a,b,c)
+
+/* Write and decode big-endian 32-bit integer values */
+static void sqlite3Fts5Put32(u8*, int);
+static int sqlite3Fts5Get32(const u8*);
+
+#define FTS5_POS2COLUMN(iPos) (int)(iPos >> 32)
+#define FTS5_POS2OFFSET(iPos) (int)(iPos & 0xFFFFFFFF)
+
+typedef struct Fts5PoslistReader Fts5PoslistReader;
+struct Fts5PoslistReader {
+  /* Variables used only by sqlite3Fts5PoslistIterXXX() functions. */
+  const u8 *a;                    /* Position list to iterate through */
+  int n;                          /* Size of buffer at a[] in bytes */
+  int i;                          /* Current offset in a[] */
+
+  u8 bFlag;                       /* For client use (any custom purpose) */
+
+  /* Output variables */
+  u8 bEof;                        /* Set to true at EOF */
+  i64 iPos;                       /* (iCol<<32) + iPos */
+};
+static int sqlite3Fts5PoslistReaderInit(
+  const u8 *a, int n,             /* Poslist buffer to iterate through */
+  Fts5PoslistReader *pIter        /* Iterator object to initialize */
+);
+static int sqlite3Fts5PoslistReaderNext(Fts5PoslistReader*);
+
+typedef struct Fts5PoslistWriter Fts5PoslistWriter;
+struct Fts5PoslistWriter {
+  i64 iPrev;
+};
+static int sqlite3Fts5PoslistWriterAppend(Fts5Buffer*, Fts5PoslistWriter*, i64);
+
+static int sqlite3Fts5PoslistNext64(
+  const u8 *a, int n,             /* Buffer containing poslist */
+  int *pi,                        /* IN/OUT: Offset within a[] */
+  i64 *piOff                      /* IN/OUT: Current offset */
+);
+
+/* Malloc utility */
+static void *sqlite3Fts5MallocZero(int *pRc, int nByte);
+static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn);
+
+/* Character set tests (like isspace(), isalpha() etc.) */
+static int sqlite3Fts5IsBareword(char t);
+
+/*
+** End of interface to code in fts5_buffer.c.
+**************************************************************************/
+
+/**************************************************************************
+** Interface to code in fts5_index.c. fts5_index.c contains contains code
+** to access the data stored in the %_data table.
+*/
+
+typedef struct Fts5Index Fts5Index;
+typedef struct Fts5IndexIter Fts5IndexIter;
+
+/*
+** Values used as part of the flags argument passed to IndexQuery().
+*/
+#define FTS5INDEX_QUERY_PREFIX     0x0001   /* Prefix query */
+#define FTS5INDEX_QUERY_DESC       0x0002   /* Docs in descending rowid order */
+#define FTS5INDEX_QUERY_TEST_NOIDX 0x0004   /* Do not use prefix index */
+#define FTS5INDEX_QUERY_SCAN       0x0008   /* Scan query (fts5vocab) */
+
+/*
+** Create/destroy an Fts5Index object.
+*/
+static int sqlite3Fts5IndexOpen(Fts5Config *pConfig, int bCreate, Fts5Index**, char**);
+static int sqlite3Fts5IndexClose(Fts5Index *p);
+
+/*
+** for(
+**   sqlite3Fts5IndexQuery(p, "token", 5, 0, 0, &pIter);
+**   0==sqlite3Fts5IterEof(pIter);
+**   sqlite3Fts5IterNext(pIter)
+** ){
+**   i64 iRowid = sqlite3Fts5IterRowid(pIter);
+** }
+*/
+
+/*
+** Open a new iterator to iterate though all rowids that match the 
+** specified token or token prefix.
+*/
+static int sqlite3Fts5IndexQuery(
+  Fts5Index *p,                   /* FTS index to query */
+  const char *pToken, int nToken, /* Token (or prefix) to query for */
+  int flags,                      /* Mask of FTS5INDEX_QUERY_X flags */
+  Fts5Colset *pColset,            /* Match these columns only */
+  Fts5IndexIter **ppIter          /* OUT: New iterator object */
+);
+
+/*
+** The various operations on open token or token prefix iterators opened
+** using sqlite3Fts5IndexQuery().
+*/
+static int sqlite3Fts5IterEof(Fts5IndexIter*);
+static int sqlite3Fts5IterNext(Fts5IndexIter*);
+static int sqlite3Fts5IterNextFrom(Fts5IndexIter*, i64 iMatch);
+static i64 sqlite3Fts5IterRowid(Fts5IndexIter*);
+static int sqlite3Fts5IterPoslist(Fts5IndexIter*,Fts5Colset*, const u8**, int*, i64*);
+static int sqlite3Fts5IterPoslistBuffer(Fts5IndexIter *pIter, Fts5Buffer *pBuf);
+
+/*
+** Close an iterator opened by sqlite3Fts5IndexQuery().
+*/
+static void sqlite3Fts5IterClose(Fts5IndexIter*);
+
+/*
+** This interface is used by the fts5vocab module.
+*/
+static const char *sqlite3Fts5IterTerm(Fts5IndexIter*, int*);
+static int sqlite3Fts5IterNextScan(Fts5IndexIter*);
+
+
+/*
+** Insert or remove data to or from the index. Each time a document is 
+** added to or removed from the index, this function is called one or more
+** times.
+**
+** For an insert, it must be called once for each token in the new document.
+** If the operation is a delete, it must be called (at least) once for each
+** unique token in the document with an iCol value less than zero. The iPos
+** argument is ignored for a delete.
+*/
+static int sqlite3Fts5IndexWrite(
+  Fts5Index *p,                   /* Index to write to */
+  int iCol,                       /* Column token appears in (-ve -> delete) */
+  int iPos,                       /* Position of token within column */
+  const char *pToken, int nToken  /* Token to add or remove to or from index */
+);
+
+/*
+** Indicate that subsequent calls to sqlite3Fts5IndexWrite() pertain to
+** document iDocid.
+*/
+static int sqlite3Fts5IndexBeginWrite(
+  Fts5Index *p,                   /* Index to write to */
+  int bDelete,                    /* True if current operation is a delete */
+  i64 iDocid                      /* Docid to add or remove data from */
+);
+
+/*
+** Flush any data stored in the in-memory hash tables to the database.
+** If the bCommit flag is true, also close any open blob handles.
+*/
+static int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit);
+
+/*
+** Discard any data stored in the in-memory hash tables. Do not write it
+** to the database. Additionally, assume that the contents of the %_data
+** table may have changed on disk. So any in-memory caches of %_data 
+** records must be invalidated.
+*/
+static int sqlite3Fts5IndexRollback(Fts5Index *p);
+
+/*
+** Get or set the "averages" values.
+*/
+static int sqlite3Fts5IndexGetAverages(Fts5Index *p, i64 *pnRow, i64 *anSize);
+static int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8*, int);
+
+/*
+** Functions called by the storage module as part of integrity-check.
+*/
+static u64 sqlite3Fts5IndexCksum(Fts5Config*,i64,int,int,const char*,int);
+static int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum);
+
+/* 
+** Called during virtual module initialization to register UDF 
+** fts5_decode() with SQLite 
+*/
+static int sqlite3Fts5IndexInit(sqlite3*);
+
+static int sqlite3Fts5IndexSetCookie(Fts5Index*, int);
+
+/*
+** Return the total number of entries read from the %_data table by 
+** this connection since it was created.
+*/
+static int sqlite3Fts5IndexReads(Fts5Index *p);
+
+static int sqlite3Fts5IndexReinit(Fts5Index *p);
+static int sqlite3Fts5IndexOptimize(Fts5Index *p);
+static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge);
+
+static int sqlite3Fts5IndexLoadConfig(Fts5Index *p);
+
+/*
+** End of interface to code in fts5_index.c.
+**************************************************************************/
+
+/**************************************************************************
+** Interface to code in fts5_varint.c. 
+*/
+static int sqlite3Fts5GetVarint32(const unsigned char *p, u32 *v);
+static int sqlite3Fts5GetVarintLen(u32 iVal);
+static u8 sqlite3Fts5GetVarint(const unsigned char*, u64*);
+static int sqlite3Fts5PutVarint(unsigned char *p, u64 v);
+
+#define fts5GetVarint32(a,b) sqlite3Fts5GetVarint32(a,(u32*)&b)
+#define fts5GetVarint    sqlite3Fts5GetVarint
+
+#define fts5FastGetVarint32(a, iOff, nVal) {      \
+  nVal = (a)[iOff++];                             \
+  if( nVal & 0x80 ){                              \
+    iOff--;                                       \
+    iOff += fts5GetVarint32(&(a)[iOff], nVal);    \
+  }                                               \
+}
+
+
+/*
+** End of interface to code in fts5_varint.c.
+**************************************************************************/
+
+
+/**************************************************************************
+** Interface to code in fts5.c. 
+*/
+
+static int sqlite3Fts5GetTokenizer(
+  Fts5Global*, 
+  const char **azArg,
+  int nArg,
+  Fts5Tokenizer**,
+  fts5_tokenizer**,
+  char **pzErr
+);
+
+static Fts5Index *sqlite3Fts5IndexFromCsrid(Fts5Global*, i64, int*);
+
+/*
+** End of interface to code in fts5.c.
+**************************************************************************/
+
+/**************************************************************************
+** Interface to code in fts5_hash.c. 
+*/
+typedef struct Fts5Hash Fts5Hash;
+
+/*
+** Create a hash table, free a hash table.
+*/
+static int sqlite3Fts5HashNew(Fts5Hash**, int *pnSize);
+static void sqlite3Fts5HashFree(Fts5Hash*);
+
+static int sqlite3Fts5HashWrite(
+  Fts5Hash*,
+  i64 iRowid,                     /* Rowid for this entry */
+  int iCol,                       /* Column token appears in (-ve -> delete) */
+  int iPos,                       /* Position of token within column */
+  char bByte,
+  const char *pToken, int nToken  /* Token to add or remove to or from index */
+);
+
+/*
+** Empty (but do not delete) a hash table.
+*/
+static void sqlite3Fts5HashClear(Fts5Hash*);
+
+static int sqlite3Fts5HashQuery(
+  Fts5Hash*,                      /* Hash table to query */
+  const char *pTerm, int nTerm,   /* Query term */
+  const u8 **ppDoclist,           /* OUT: Pointer to doclist for pTerm */
+  int *pnDoclist                  /* OUT: Size of doclist in bytes */
+);
+
+static int sqlite3Fts5HashScanInit(
+  Fts5Hash*,                      /* Hash table to query */
+  const char *pTerm, int nTerm    /* Query prefix */
+);
+static void sqlite3Fts5HashScanNext(Fts5Hash*);
+static int sqlite3Fts5HashScanEof(Fts5Hash*);
+static void sqlite3Fts5HashScanEntry(Fts5Hash *,
+  const char **pzTerm,            /* OUT: term (nul-terminated) */
+  const u8 **ppDoclist,           /* OUT: pointer to doclist */
+  int *pnDoclist                  /* OUT: size of doclist in bytes */
+);
+
+
+/*
+** End of interface to code in fts5_hash.c.
+**************************************************************************/
+
+/**************************************************************************
+** Interface to code in fts5_storage.c. fts5_storage.c contains contains 
+** code to access the data stored in the %_content and %_docsize tables.
+*/
+
+#define FTS5_STMT_SCAN_ASC  0     /* SELECT rowid, * FROM ... ORDER BY 1 ASC */
+#define FTS5_STMT_SCAN_DESC 1     /* SELECT rowid, * FROM ... ORDER BY 1 DESC */
+#define FTS5_STMT_LOOKUP    2     /* SELECT rowid, * FROM ... WHERE rowid=? */
+
+typedef struct Fts5Storage Fts5Storage;
+
+static int sqlite3Fts5StorageOpen(Fts5Config*, Fts5Index*, int, Fts5Storage**, char**);
+static int sqlite3Fts5StorageClose(Fts5Storage *p);
+static int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName);
+
+static int sqlite3Fts5DropAll(Fts5Config*);
+static int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **);
+
+static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64);
+static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*);
+static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64);
+
+static int sqlite3Fts5StorageIntegrity(Fts5Storage *p);
+
+static int sqlite3Fts5StorageStmt(Fts5Storage *p, int eStmt, sqlite3_stmt**, char**);
+static void sqlite3Fts5StorageStmtRelease(Fts5Storage *p, int eStmt, sqlite3_stmt*);
+
+static int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol);
+static int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnAvg);
+static int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow);
+
+static int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit);
+static int sqlite3Fts5StorageRollback(Fts5Storage *p);
+
+static int sqlite3Fts5StorageConfigValue(
+    Fts5Storage *p, const char*, sqlite3_value*, int
+);
+
+static int sqlite3Fts5StorageSpecialDelete(Fts5Storage *p, i64 iDel, sqlite3_value**);
+
+static int sqlite3Fts5StorageDeleteAll(Fts5Storage *p);
+static int sqlite3Fts5StorageRebuild(Fts5Storage *p);
+static int sqlite3Fts5StorageOptimize(Fts5Storage *p);
+static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge);
+
+/*
+** End of interface to code in fts5_storage.c.
+**************************************************************************/
+
+
+/**************************************************************************
+** Interface to code in fts5_expr.c. 
+*/
+typedef struct Fts5Expr Fts5Expr;
+typedef struct Fts5ExprNode Fts5ExprNode;
+typedef struct Fts5Parse Fts5Parse;
+typedef struct Fts5Token Fts5Token;
+typedef struct Fts5ExprPhrase Fts5ExprPhrase;
+typedef struct Fts5ExprNearset Fts5ExprNearset;
+
+struct Fts5Token {
+  const char *p;                  /* Token text (not NULL terminated) */
+  int n;                          /* Size of buffer p in bytes */
+};
+
+/* Parse a MATCH expression. */
+static int sqlite3Fts5ExprNew(
+  Fts5Config *pConfig, 
+  const char *zExpr,
+  Fts5Expr **ppNew, 
+  char **pzErr
+);
+
+/*
+** for(rc = sqlite3Fts5ExprFirst(pExpr, pIdx, bDesc);
+**     rc==SQLITE_OK && 0==sqlite3Fts5ExprEof(pExpr);
+**     rc = sqlite3Fts5ExprNext(pExpr)
+** ){
+**   // The document with rowid iRowid matches the expression!
+**   i64 iRowid = sqlite3Fts5ExprRowid(pExpr);
+** }
+*/
+static int sqlite3Fts5ExprFirst(Fts5Expr*, Fts5Index *pIdx, i64 iMin, int bDesc);
+static int sqlite3Fts5ExprNext(Fts5Expr*, i64 iMax);
+static int sqlite3Fts5ExprEof(Fts5Expr*);
+static i64 sqlite3Fts5ExprRowid(Fts5Expr*);
+
+static void sqlite3Fts5ExprFree(Fts5Expr*);
+
+/* Called during startup to register a UDF with SQLite */
+static int sqlite3Fts5ExprInit(Fts5Global*, sqlite3*);
+
+static int sqlite3Fts5ExprPhraseCount(Fts5Expr*);
+static int sqlite3Fts5ExprPhraseSize(Fts5Expr*, int iPhrase);
+static int sqlite3Fts5ExprPoslist(Fts5Expr*, int, const u8 **);
+
+static int sqlite3Fts5ExprClonePhrase(Fts5Config*, Fts5Expr*, int, Fts5Expr**);
+
+/*******************************************
+** The fts5_expr.c API above this point is used by the other hand-written
+** C code in this module. The interfaces below this point are called by
+** the parser code in fts5parse.y.  */
+
+static void sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...);
+
+static Fts5ExprNode *sqlite3Fts5ParseNode(
+  Fts5Parse *pParse,
+  int eType,
+  Fts5ExprNode *pLeft,
+  Fts5ExprNode *pRight,
+  Fts5ExprNearset *pNear
+);
+
+static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
+  Fts5Parse *pParse, 
+  Fts5ExprPhrase *pPhrase, 
+  Fts5Token *pToken,
+  int bPrefix
+);
+
+static Fts5ExprNearset *sqlite3Fts5ParseNearset(
+  Fts5Parse*, 
+  Fts5ExprNearset*,
+  Fts5ExprPhrase* 
+);
+
+static Fts5Colset *sqlite3Fts5ParseColset(
+  Fts5Parse*, 
+  Fts5Colset*, 
+  Fts5Token *
+);
+
+static void sqlite3Fts5ParsePhraseFree(Fts5ExprPhrase*);
+static void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset*);
+static void sqlite3Fts5ParseNodeFree(Fts5ExprNode*);
+
+static void sqlite3Fts5ParseSetDistance(Fts5Parse*, Fts5ExprNearset*, Fts5Token*);
+static void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNearset*, Fts5Colset*);
+static void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p);
+static void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token*);
+
+/*
+** End of interface to code in fts5_expr.c.
+**************************************************************************/
+
+
+
+/**************************************************************************
+** Interface to code in fts5_aux.c. 
+*/
+
+static int sqlite3Fts5AuxInit(fts5_api*);
+/*
+** End of interface to code in fts5_aux.c.
+**************************************************************************/
+
+/**************************************************************************
+** Interface to code in fts5_tokenizer.c. 
+*/
+
+static int sqlite3Fts5TokenizerInit(fts5_api*);
+/*
+** End of interface to code in fts5_tokenizer.c.
+**************************************************************************/
+
+/**************************************************************************
+** Interface to code in fts5_vocab.c. 
+*/
+
+static int sqlite3Fts5VocabInit(Fts5Global*, sqlite3*);
+
+/*
+** End of interface to code in fts5_vocab.c.
+**************************************************************************/
+
+
+/**************************************************************************
+** 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);
+/*
+** End of interface to code in fts5_unicode2.c.
+**************************************************************************/
+
+#endif
+
+#define FTS5_OR                               1
+#define FTS5_AND                              2
+#define FTS5_NOT                              3
+#define FTS5_TERM                             4
+#define FTS5_COLON                            5
+#define FTS5_LP                               6
+#define FTS5_RP                               7
+#define FTS5_LCP                              8
+#define FTS5_RCP                              9
+#define FTS5_STRING                          10
+#define FTS5_COMMA                           11
+#define FTS5_PLUS                            12
+#define FTS5_STAR                            13
+
+/* Driver template for the LEMON parser generator.
+** The author disclaims copyright to this source code.
+**
+** This version of "lempar.c" is modified, slightly, for use by SQLite.
+** The only modifications are the addition of a couple of NEVER()
+** macros to disable tests that are needed in the case of a general
+** LALR(1) grammar but which are always false in the
+** specific grammar used by SQLite.
+*/
+/* First off, code is included that follows the "include" declaration
+** in the input grammar file. */
+/* #include <stdio.h> */
+
+
+/*
+** Disable all error recovery processing in the parser push-down
+** automaton.
+*/
+#define fts5YYNOERRORRECOVERY 1
+
+/*
+** Make fts5yytestcase() the same as testcase()
+*/
+#define fts5yytestcase(X) testcase(X)
+
+/* Next is all token values, in a form suitable for use by makeheaders.
+** This section will be null unless lemon is run with the -m switch.
+*/
+/* 
+** These constants (all generated automatically by the parser generator)
+** specify the various kinds of tokens (terminals) that the parser
+** understands. 
+**
+** Each symbol here is a terminal symbol in the grammar.
+*/
+/* Make sure the INTERFACE macro is defined.
+*/
+#ifndef INTERFACE
+# define INTERFACE 1
+#endif
+/* The next thing included is series of defines which control
+** various aspects of the generated parser.
+**    fts5YYCODETYPE         is the data type used for storing terminal
+**                       and nonterminal numbers.  "unsigned char" is
+**                       used if there are fewer than 250 terminals
+**                       and nonterminals.  "int" is used otherwise.
+**    fts5YYNOCODE           is a number of type fts5YYCODETYPE which corresponds
+**                       to no legal terminal or nonterminal number.  This
+**                       number is used to fill in empty slots of the hash 
+**                       table.
+**    fts5YYFALLBACK         If defined, this indicates that one or more tokens
+**                       have fall-back values which should be used if the
+**                       original value of the token will not parse.
+**    fts5YYACTIONTYPE       is the data type used for storing terminal
+**                       and nonterminal numbers.  "unsigned char" is
+**                       used if there are fewer than 250 rules and
+**                       states combined.  "int" is used otherwise.
+**    sqlite3Fts5ParserFTS5TOKENTYPE     is the data type used for minor tokens given 
+**                       directly to the parser from the tokenizer.
+**    fts5YYMINORTYPE        is the data type used for all minor tokens.
+**                       This is typically a union of many types, one of
+**                       which is sqlite3Fts5ParserFTS5TOKENTYPE.  The entry in the union
+**                       for base tokens is called "fts5yy0".
+**    fts5YYSTACKDEPTH       is the maximum depth of the parser's stack.  If
+**                       zero the stack is dynamically sized using realloc()
+**    sqlite3Fts5ParserARG_SDECL     A static variable declaration for the %extra_argument
+**    sqlite3Fts5ParserARG_PDECL     A parameter declaration for the %extra_argument
+**    sqlite3Fts5ParserARG_STORE     Code to store %extra_argument into fts5yypParser
+**    sqlite3Fts5ParserARG_FETCH     Code to extract %extra_argument from fts5yypParser
+**    fts5YYERRORSYMBOL      is the code number of the error symbol.  If not
+**                       defined, then do no error processing.
+**    fts5YYNSTATE           the combined number of states.
+**    fts5YYNRULE            the number of rules in the grammar
+**    fts5YY_MAX_SHIFT       Maximum value for shift actions
+**    fts5YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions
+**    fts5YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions
+**    fts5YY_MIN_REDUCE      Maximum value for reduce actions
+**    fts5YY_ERROR_ACTION    The fts5yy_action[] code for syntax error
+**    fts5YY_ACCEPT_ACTION   The fts5yy_action[] code for accept
+**    fts5YY_NO_ACTION       The fts5yy_action[] code for no-op
+*/
+#define fts5YYCODETYPE unsigned char
+#define fts5YYNOCODE 27
+#define fts5YYACTIONTYPE unsigned char
+#define sqlite3Fts5ParserFTS5TOKENTYPE Fts5Token
+typedef union {
+  int fts5yyinit;
+  sqlite3Fts5ParserFTS5TOKENTYPE fts5yy0;
+  Fts5Colset* fts5yy3;
+  Fts5ExprPhrase* fts5yy11;
+  Fts5ExprNode* fts5yy18;
+  int fts5yy20;
+  Fts5ExprNearset* fts5yy26;
+} fts5YYMINORTYPE;
+#ifndef fts5YYSTACKDEPTH
+#define fts5YYSTACKDEPTH 100
+#endif
+#define sqlite3Fts5ParserARG_SDECL Fts5Parse *pParse;
+#define sqlite3Fts5ParserARG_PDECL ,Fts5Parse *pParse
+#define sqlite3Fts5ParserARG_FETCH Fts5Parse *pParse = fts5yypParser->pParse
+#define sqlite3Fts5ParserARG_STORE fts5yypParser->pParse = pParse
+#define fts5YYNSTATE             26
+#define fts5YYNRULE              24
+#define fts5YY_MAX_SHIFT         25
+#define fts5YY_MIN_SHIFTREDUCE   40
+#define fts5YY_MAX_SHIFTREDUCE   63
+#define fts5YY_MIN_REDUCE        64
+#define fts5YY_MAX_REDUCE        87
+#define fts5YY_ERROR_ACTION      88
+#define fts5YY_ACCEPT_ACTION     89
+#define fts5YY_NO_ACTION         90
+
+/* The fts5yyzerominor constant is used to initialize instances of
+** fts5YYMINORTYPE objects to zero. */
+static const fts5YYMINORTYPE fts5yyzerominor = { 0 };
+
+/* Define the fts5yytestcase() macro to be a no-op if is not already defined
+** otherwise.
+**
+** Applications can choose to define fts5yytestcase() in the %include section
+** to a macro that can assist in verifying code coverage.  For production
+** code the fts5yytestcase() macro should be turned off.  But it is useful
+** for testing.
+*/
+#ifndef fts5yytestcase
+# define fts5yytestcase(X)
+#endif
+
+
+/* Next are the tables used to determine what action to take based on the
+** current state and lookahead token.  These tables are used to implement
+** functions that take a state number and lookahead value and return an
+** action integer.  
+**
+** Suppose the action integer is N.  Then the action is determined as
+** follows
+**
+**   0 <= N <= fts5YY_MAX_SHIFT             Shift N.  That is, push the lookahead
+**                                      token onto the stack and goto state N.
+**
+**   N between fts5YY_MIN_SHIFTREDUCE       Shift to an arbitrary state then
+**     and fts5YY_MAX_SHIFTREDUCE           reduce by rule N-fts5YY_MIN_SHIFTREDUCE.
+**
+**   N between fts5YY_MIN_REDUCE            Reduce by rule N-fts5YY_MIN_REDUCE
+**     and fts5YY_MAX_REDUCE
+
+**   N == fts5YY_ERROR_ACTION               A syntax error has occurred.
+**
+**   N == fts5YY_ACCEPT_ACTION              The parser accepts its input.
+**
+**   N == fts5YY_NO_ACTION                  No such action.  Denotes unused
+**                                      slots in the fts5yy_action[] table.
+**
+** The action table is constructed as a single large table named fts5yy_action[].
+** Given state S and lookahead X, the action is computed as
+**
+**      fts5yy_action[ fts5yy_shift_ofst[S] + X ]
+**
+** If the index value fts5yy_shift_ofst[S]+X is out of range or if the value
+** fts5yy_lookahead[fts5yy_shift_ofst[S]+X] is not equal to X or if fts5yy_shift_ofst[S]
+** is equal to fts5YY_SHIFT_USE_DFLT, it means that the action is not in the table
+** and that fts5yy_default[S] should be used instead.  
+**
+** The formula above is for computing the action when the lookahead is
+** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
+** a reduce action) then the fts5yy_reduce_ofst[] array is used in place of
+** the fts5yy_shift_ofst[] array and fts5YY_REDUCE_USE_DFLT is used in place of
+** fts5YY_SHIFT_USE_DFLT.
+**
+** The following are the tables generated in this section:
+**
+**  fts5yy_action[]        A single table containing all actions.
+**  fts5yy_lookahead[]     A table containing the lookahead for each entry in
+**                     fts5yy_action.  Used to detect hash collisions.
+**  fts5yy_shift_ofst[]    For each state, the offset into fts5yy_action for
+**                     shifting terminals.
+**  fts5yy_reduce_ofst[]   For each state, the offset into fts5yy_action for
+**                     shifting non-terminals after a reduce.
+**  fts5yy_default[]       Default action for each state.
+*/
+#define fts5YY_ACTTAB_COUNT (78)
+static const fts5YYACTIONTYPE fts5yy_action[] = {
+ /*     0 */    89,   15,   46,    5,   48,   24,   12,   19,   23,   14,
+ /*    10 */    46,    5,   48,   24,   20,   21,   23,   43,   46,    5,
+ /*    20 */    48,   24,    6,   18,   23,   17,   46,    5,   48,   24,
+ /*    30 */    75,    7,   23,   25,   46,    5,   48,   24,   62,   47,
+ /*    40 */    23,   48,   24,    7,   11,   23,    9,    3,    4,    2,
+ /*    50 */    62,   50,   52,   44,   64,    3,    4,    2,   49,    4,
+ /*    60 */     2,    1,   23,   11,   16,    9,   12,    2,   10,   61,
+ /*    70 */    53,   59,   62,   60,   22,   13,   55,    8,
+};
+static const fts5YYCODETYPE fts5yy_lookahead[] = {
+ /*     0 */    15,   16,   17,   18,   19,   20,   10,   11,   23,   16,
+ /*    10 */    17,   18,   19,   20,   23,   24,   23,   16,   17,   18,
+ /*    20 */    19,   20,   22,   23,   23,   16,   17,   18,   19,   20,
+ /*    30 */     5,    6,   23,   16,   17,   18,   19,   20,   13,   17,
+ /*    40 */    23,   19,   20,    6,    8,   23,   10,    1,    2,    3,
+ /*    50 */    13,    9,   10,    7,    0,    1,    2,    3,   19,    2,
+ /*    60 */     3,    6,   23,    8,   21,   10,   10,    3,   10,   25,
+ /*    70 */    10,   10,   13,   25,   12,   10,    7,    5,
+};
+#define fts5YY_SHIFT_USE_DFLT (-5)
+#define fts5YY_SHIFT_COUNT (25)
+#define fts5YY_SHIFT_MIN   (-4)
+#define fts5YY_SHIFT_MAX   (72)
+static const signed char fts5yy_shift_ofst[] = {
+ /*     0 */    55,   55,   55,   55,   55,   36,   -4,   56,   58,   25,
+ /*    10 */    37,   60,   59,   59,   46,   54,   42,   57,   62,   61,
+ /*    20 */    62,   69,   65,   62,   72,   64,
+};
+#define fts5YY_REDUCE_USE_DFLT (-16)
+#define fts5YY_REDUCE_COUNT (13)
+#define fts5YY_REDUCE_MIN   (-15)
+#define fts5YY_REDUCE_MAX   (48)
+static const signed char fts5yy_reduce_ofst[] = {
+ /*     0 */   -15,   -7,    1,    9,   17,   22,   -9,    0,   39,   44,
+ /*    10 */    44,   43,   44,   48,
+};
+static const fts5YYACTIONTYPE fts5yy_default[] = {
+ /*     0 */    88,   88,   88,   88,   88,   69,   82,   88,   88,   87,
+ /*    10 */    87,   88,   87,   87,   88,   88,   88,   66,   80,   88,
+ /*    20 */    81,   88,   88,   78,   88,   65,
+};
+
+/* The next table maps tokens into fallback tokens.  If a construct
+** like the following:
+** 
+**      %fallback ID X Y Z.
+**
+** appears in the grammar, then ID becomes a fallback token for X, Y,
+** and Z.  Whenever one of the tokens X, Y, or Z is input to the parser
+** but it does not parse, the type of the token is changed to ID and
+** the parse is retried before an error is thrown.
+*/
+#ifdef fts5YYFALLBACK
+static const fts5YYCODETYPE fts5yyFallback[] = {
+};
+#endif /* fts5YYFALLBACK */
+
+/* The following structure represents a single element of the
+** parser's stack.  Information stored includes:
+**
+**   +  The state number for the parser at this level of the stack.
+**
+**   +  The value of the token stored at this level of the stack.
+**      (In other words, the "major" token.)
+**
+**   +  The semantic value stored at this level of the stack.  This is
+**      the information used by the action routines in the grammar.
+**      It is sometimes called the "minor" token.
+**
+** After the "shift" half of a SHIFTREDUCE action, the stateno field
+** actually contains the reduce action for the second half of the
+** SHIFTREDUCE.
+*/
+struct fts5yyStackEntry {
+  fts5YYACTIONTYPE stateno;  /* The state-number, or reduce action in SHIFTREDUCE */
+  fts5YYCODETYPE major;      /* The major token value.  This is the code
+                         ** number for the token at this stack level */
+  fts5YYMINORTYPE minor;     /* The user-supplied minor token value.  This
+                         ** is the value of the token  */
+};
+typedef struct fts5yyStackEntry fts5yyStackEntry;
+
+/* The state of the parser is completely contained in an instance of
+** the following structure */
+struct fts5yyParser {
+  int fts5yyidx;                    /* Index of top element in stack */
+#ifdef fts5YYTRACKMAXSTACKDEPTH
+  int fts5yyidxMax;                 /* Maximum value of fts5yyidx */
+#endif
+  int fts5yyerrcnt;                 /* Shifts left before out of the error */
+  sqlite3Fts5ParserARG_SDECL                /* A place to hold %extra_argument */
+#if fts5YYSTACKDEPTH<=0
+  int fts5yystksz;                  /* Current side of the stack */
+  fts5yyStackEntry *fts5yystack;        /* The parser's stack */
+#else
+  fts5yyStackEntry fts5yystack[fts5YYSTACKDEPTH];  /* The parser's stack */
+#endif
+};
+typedef struct fts5yyParser fts5yyParser;
+
+#ifndef NDEBUG
+/* #include <stdio.h> */
+static FILE *fts5yyTraceFILE = 0;
+static char *fts5yyTracePrompt = 0;
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* 
+** Turn parser tracing on by giving a stream to which to write the trace
+** and a prompt to preface each trace message.  Tracing is turned off
+** by making either argument NULL 
+**
+** Inputs:
+** <ul>
+** <li> A FILE* to which trace output should be written.
+**      If NULL, then tracing is turned off.
+** <li> A prefix string written at the beginning of every
+**      line of trace output.  If NULL, then tracing is
+**      turned off.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+static void sqlite3Fts5ParserTrace(FILE *TraceFILE, char *zTracePrompt){
+  fts5yyTraceFILE = TraceFILE;
+  fts5yyTracePrompt = zTracePrompt;
+  if( fts5yyTraceFILE==0 ) fts5yyTracePrompt = 0;
+  else if( fts5yyTracePrompt==0 ) fts5yyTraceFILE = 0;
+}
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing shifts, the names of all terminals and nonterminals
+** are required.  The following table supplies these names */
+static const char *const fts5yyTokenName[] = { 
+  "$",             "OR",            "AND",           "NOT",         
+  "TERM",          "COLON",         "LP",            "RP",          
+  "LCP",           "RCP",           "STRING",        "COMMA",       
+  "PLUS",          "STAR",          "error",         "input",       
+  "expr",          "cnearset",      "exprlist",      "nearset",     
+  "colset",        "colsetlist",    "nearphrases",   "phrase",      
+  "neardist_opt",  "star_opt",    
+};
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing reduce actions, the names of all rules are required.
+*/
+static const char *const fts5yyRuleName[] = {
+ /*   0 */ "input ::= expr",
+ /*   1 */ "expr ::= expr AND expr",
+ /*   2 */ "expr ::= expr OR expr",
+ /*   3 */ "expr ::= expr NOT expr",
+ /*   4 */ "expr ::= LP expr RP",
+ /*   5 */ "expr ::= exprlist",
+ /*   6 */ "exprlist ::= cnearset",
+ /*   7 */ "exprlist ::= exprlist cnearset",
+ /*   8 */ "cnearset ::= nearset",
+ /*   9 */ "cnearset ::= colset COLON nearset",
+ /*  10 */ "colset ::= LCP colsetlist RCP",
+ /*  11 */ "colset ::= STRING",
+ /*  12 */ "colsetlist ::= colsetlist STRING",
+ /*  13 */ "colsetlist ::= STRING",
+ /*  14 */ "nearset ::= phrase",
+ /*  15 */ "nearset ::= STRING LP nearphrases neardist_opt RP",
+ /*  16 */ "nearphrases ::= phrase",
+ /*  17 */ "nearphrases ::= nearphrases phrase",
+ /*  18 */ "neardist_opt ::=",
+ /*  19 */ "neardist_opt ::= COMMA STRING",
+ /*  20 */ "phrase ::= phrase PLUS STRING star_opt",
+ /*  21 */ "phrase ::= STRING star_opt",
+ /*  22 */ "star_opt ::= STAR",
+ /*  23 */ "star_opt ::=",
+};
+#endif /* NDEBUG */
+
+
+#if fts5YYSTACKDEPTH<=0
+/*
+** Try to increase the size of the parser stack.
+*/
+static void fts5yyGrowStack(fts5yyParser *p){
+  int newSize;
+  fts5yyStackEntry *pNew;
+
+  newSize = p->fts5yystksz*2 + 100;
+  pNew = realloc(p->fts5yystack, newSize*sizeof(pNew[0]));
+  if( pNew ){
+    p->fts5yystack = pNew;
+    p->fts5yystksz = newSize;
+#ifndef NDEBUG
+    if( fts5yyTraceFILE ){
+      fprintf(fts5yyTraceFILE,"%sStack grows to %d entries!\n",
+              fts5yyTracePrompt, p->fts5yystksz);
+    }
+#endif
+  }
+}
+#endif
+
+/* 
+** This function allocates a new parser.
+** The only argument is a pointer to a function which works like
+** malloc.
+**
+** Inputs:
+** A pointer to the function used to allocate memory.
+**
+** Outputs:
+** A pointer to a parser.  This pointer is used in subsequent calls
+** to sqlite3Fts5Parser and sqlite3Fts5ParserFree.
+*/
+static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(u64)){
+  fts5yyParser *pParser;
+  pParser = (fts5yyParser*)(*mallocProc)( (u64)sizeof(fts5yyParser) );
+  if( pParser ){
+    pParser->fts5yyidx = -1;
+#ifdef fts5YYTRACKMAXSTACKDEPTH
+    pParser->fts5yyidxMax = 0;
+#endif
+#if fts5YYSTACKDEPTH<=0
+    pParser->fts5yystack = NULL;
+    pParser->fts5yystksz = 0;
+    fts5yyGrowStack(pParser);
+#endif
+  }
+  return pParser;
+}
+
+/* The following function deletes the value associated with a
+** symbol.  The symbol can be either a terminal or nonterminal.
+** "fts5yymajor" is the symbol code, and "fts5yypminor" is a pointer to
+** the value.
+*/
+static void fts5yy_destructor(
+  fts5yyParser *fts5yypParser,    /* The parser */
+  fts5YYCODETYPE fts5yymajor,     /* Type code for object to destroy */
+  fts5YYMINORTYPE *fts5yypminor   /* The object to be destroyed */
+){
+  sqlite3Fts5ParserARG_FETCH;
+  switch( fts5yymajor ){
+    /* Here is inserted the actions which take place when a
+    ** terminal or non-terminal is destroyed.  This can happen
+    ** when the symbol is popped from the stack during a
+    ** reduce or during error processing or when a parser is 
+    ** being destroyed before it is finished parsing.
+    **
+    ** Note: during a reduce, the only symbols destroyed are those
+    ** which appear on the RHS of the rule, but which are not used
+    ** inside the C code.
+    */
+    case 15: /* input */
+{
+ (void)pParse; 
+}
+      break;
+    case 16: /* expr */
+    case 17: /* cnearset */
+    case 18: /* exprlist */
+{
+ sqlite3Fts5ParseNodeFree((fts5yypminor->fts5yy18)); 
+}
+      break;
+    case 19: /* nearset */
+    case 22: /* nearphrases */
+{
+ sqlite3Fts5ParseNearsetFree((fts5yypminor->fts5yy26)); 
+}
+      break;
+    case 20: /* colset */
+    case 21: /* colsetlist */
+{
+ sqlite3_free((fts5yypminor->fts5yy3)); 
+}
+      break;
+    case 23: /* phrase */
+{
+ sqlite3Fts5ParsePhraseFree((fts5yypminor->fts5yy11)); 
+}
+      break;
+    default:  break;   /* If no destructor action specified: do nothing */
+  }
+}
+
+/*
+** Pop the parser's stack once.
+**
+** If there is a destructor routine associated with the token which
+** is popped from the stack, then call it.
+**
+** Return the major token number for the symbol popped.
+*/
+static int fts5yy_pop_parser_stack(fts5yyParser *pParser){
+  fts5YYCODETYPE fts5yymajor;
+  fts5yyStackEntry *fts5yytos = &pParser->fts5yystack[pParser->fts5yyidx];
+
+  /* There is no mechanism by which the parser stack can be popped below
+  ** empty in SQLite.  */
+  assert( pParser->fts5yyidx>=0 );
+#ifndef NDEBUG
+  if( fts5yyTraceFILE && pParser->fts5yyidx>=0 ){
+    fprintf(fts5yyTraceFILE,"%sPopping %s\n",
+      fts5yyTracePrompt,
+      fts5yyTokenName[fts5yytos->major]);
+  }
+#endif
+  fts5yymajor = fts5yytos->major;
+  fts5yy_destructor(pParser, fts5yymajor, &fts5yytos->minor);
+  pParser->fts5yyidx--;
+  return fts5yymajor;
+}
+
+/* 
+** Deallocate and destroy a parser.  Destructors are all called for
+** all stack elements before shutting the parser down.
+**
+** Inputs:
+** <ul>
+** <li>  A pointer to the parser.  This should be a pointer
+**       obtained from sqlite3Fts5ParserAlloc.
+** <li>  A pointer to a function used to reclaim memory obtained
+**       from malloc.
+** </ul>
+*/
+static void sqlite3Fts5ParserFree(
+  void *p,                    /* The parser to be deleted */
+  void (*freeProc)(void*)     /* Function used to reclaim memory */
+){
+  fts5yyParser *pParser = (fts5yyParser*)p;
+  /* In SQLite, we never try to destroy a parser that was not successfully
+  ** created in the first place. */
+  if( NEVER(pParser==0) ) return;
+  while( pParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(pParser);
+#if fts5YYSTACKDEPTH<=0
+  free(pParser->fts5yystack);
+#endif
+  (*freeProc)((void*)pParser);
+}
+
+/*
+** Return the peak depth of the stack for a parser.
+*/
+#ifdef fts5YYTRACKMAXSTACKDEPTH
+static int sqlite3Fts5ParserStackPeak(void *p){
+  fts5yyParser *pParser = (fts5yyParser*)p;
+  return pParser->fts5yyidxMax;
+}
+#endif
+
+/*
+** Find the appropriate action for a parser given the terminal
+** look-ahead token iLookAhead.
+**
+** If the look-ahead token is fts5YYNOCODE, then check to see if the action is
+** independent of the look-ahead.  If it is, return the action, otherwise
+** return fts5YY_NO_ACTION.
+*/
+static int fts5yy_find_shift_action(
+  fts5yyParser *pParser,        /* The parser */
+  fts5YYCODETYPE iLookAhead     /* The look-ahead token */
+){
+  int i;
+  int stateno = pParser->fts5yystack[pParser->fts5yyidx].stateno;
+  if( stateno>=fts5YY_MIN_REDUCE ) return stateno;
+  assert( stateno <= fts5YY_SHIFT_COUNT );
+  i = fts5yy_shift_ofst[stateno];
+  if( i==fts5YY_SHIFT_USE_DFLT ) return fts5yy_default[stateno];
+  assert( iLookAhead!=fts5YYNOCODE );
+  i += iLookAhead;
+  if( i<0 || i>=fts5YY_ACTTAB_COUNT || fts5yy_lookahead[i]!=iLookAhead ){
+    if( iLookAhead>0 ){
+#ifdef fts5YYFALLBACK
+      fts5YYCODETYPE iFallback;            /* Fallback token */
+      if( iLookAhead<sizeof(fts5yyFallback)/sizeof(fts5yyFallback[0])
+             && (iFallback = fts5yyFallback[iLookAhead])!=0 ){
+#ifndef NDEBUG
+        if( fts5yyTraceFILE ){
+          fprintf(fts5yyTraceFILE, "%sFALLBACK %s => %s\n",
+             fts5yyTracePrompt, fts5yyTokenName[iLookAhead], fts5yyTokenName[iFallback]);
+        }
+#endif
+        return fts5yy_find_shift_action(pParser, iFallback);
+      }
+#endif
+#ifdef fts5YYWILDCARD
+      {
+        int j = i - iLookAhead + fts5YYWILDCARD;
+        if( 
+#if fts5YY_SHIFT_MIN+fts5YYWILDCARD<0
+          j>=0 &&
+#endif
+#if fts5YY_SHIFT_MAX+fts5YYWILDCARD>=fts5YY_ACTTAB_COUNT
+          j<fts5YY_ACTTAB_COUNT &&
+#endif
+          fts5yy_lookahead[j]==fts5YYWILDCARD
+        ){
+#ifndef NDEBUG
+          if( fts5yyTraceFILE ){
+            fprintf(fts5yyTraceFILE, "%sWILDCARD %s => %s\n",
+               fts5yyTracePrompt, fts5yyTokenName[iLookAhead], fts5yyTokenName[fts5YYWILDCARD]);
+          }
+#endif /* NDEBUG */
+          return fts5yy_action[j];
+        }
+      }
+#endif /* fts5YYWILDCARD */
+    }
+    return fts5yy_default[stateno];
+  }else{
+    return fts5yy_action[i];
+  }
+}
+
+/*
+** Find the appropriate action for a parser given the non-terminal
+** look-ahead token iLookAhead.
+**
+** If the look-ahead token is fts5YYNOCODE, then check to see if the action is
+** independent of the look-ahead.  If it is, return the action, otherwise
+** return fts5YY_NO_ACTION.
+*/
+static int fts5yy_find_reduce_action(
+  int stateno,              /* Current state number */
+  fts5YYCODETYPE iLookAhead     /* The look-ahead token */
+){
+  int i;
+#ifdef fts5YYERRORSYMBOL
+  if( stateno>fts5YY_REDUCE_COUNT ){
+    return fts5yy_default[stateno];
+  }
+#else
+  assert( stateno<=fts5YY_REDUCE_COUNT );
+#endif
+  i = fts5yy_reduce_ofst[stateno];
+  assert( i!=fts5YY_REDUCE_USE_DFLT );
+  assert( iLookAhead!=fts5YYNOCODE );
+  i += iLookAhead;
+#ifdef fts5YYERRORSYMBOL
+  if( i<0 || i>=fts5YY_ACTTAB_COUNT || fts5yy_lookahead[i]!=iLookAhead ){
+    return fts5yy_default[stateno];
+  }
+#else
+  assert( i>=0 && i<fts5YY_ACTTAB_COUNT );
+  assert( fts5yy_lookahead[i]==iLookAhead );
+#endif
+  return fts5yy_action[i];
+}
+
+/*
+** The following routine is called if the stack overflows.
+*/
+static void fts5yyStackOverflow(fts5yyParser *fts5yypParser, fts5YYMINORTYPE *fts5yypMinor){
+   sqlite3Fts5ParserARG_FETCH;
+   fts5yypParser->fts5yyidx--;
+#ifndef NDEBUG
+   if( fts5yyTraceFILE ){
+     fprintf(fts5yyTraceFILE,"%sStack Overflow!\n",fts5yyTracePrompt);
+   }
+#endif
+   while( fts5yypParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(fts5yypParser);
+   /* Here code is inserted which will execute if the parser
+   ** stack every overflows */
+
+  assert( 0 );
+   sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument var */
+}
+
+/*
+** Print tracing information for a SHIFT action
+*/
+#ifndef NDEBUG
+static void fts5yyTraceShift(fts5yyParser *fts5yypParser, int fts5yyNewState){
+  if( fts5yyTraceFILE ){
+    int i;
+    if( fts5yyNewState<fts5YYNSTATE ){
+      fprintf(fts5yyTraceFILE,"%sShift %d\n",fts5yyTracePrompt,fts5yyNewState);
+      fprintf(fts5yyTraceFILE,"%sStack:",fts5yyTracePrompt);
+      for(i=1; i<=fts5yypParser->fts5yyidx; i++)
+        fprintf(fts5yyTraceFILE," %s",fts5yyTokenName[fts5yypParser->fts5yystack[i].major]);
+      fprintf(fts5yyTraceFILE,"\n");
+    }else{
+      fprintf(fts5yyTraceFILE,"%sShift *\n",fts5yyTracePrompt);
+    }
+  }
+}
+#else
+# define fts5yyTraceShift(X,Y)
+#endif
+
+/*
+** Perform a shift action.  Return the number of errors.
+*/
+static void fts5yy_shift(
+  fts5yyParser *fts5yypParser,          /* The parser to be shifted */
+  int fts5yyNewState,               /* The new state to shift in */
+  int fts5yyMajor,                  /* The major token to shift in */
+  fts5YYMINORTYPE *fts5yypMinor         /* Pointer to the minor token to shift in */
+){
+  fts5yyStackEntry *fts5yytos;
+  fts5yypParser->fts5yyidx++;
+#ifdef fts5YYTRACKMAXSTACKDEPTH
+  if( fts5yypParser->fts5yyidx>fts5yypParser->fts5yyidxMax ){
+    fts5yypParser->fts5yyidxMax = fts5yypParser->fts5yyidx;
+  }
+#endif
+#if fts5YYSTACKDEPTH>0 
+  if( fts5yypParser->fts5yyidx>=fts5YYSTACKDEPTH ){
+    fts5yyStackOverflow(fts5yypParser, fts5yypMinor);
+    return;
+  }
+#else
+  if( fts5yypParser->fts5yyidx>=fts5yypParser->fts5yystksz ){
+    fts5yyGrowStack(fts5yypParser);
+    if( fts5yypParser->fts5yyidx>=fts5yypParser->fts5yystksz ){
+      fts5yyStackOverflow(fts5yypParser, fts5yypMinor);
+      return;
+    }
+  }
+#endif
+  fts5yytos = &fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx];
+  fts5yytos->stateno = (fts5YYACTIONTYPE)fts5yyNewState;
+  fts5yytos->major = (fts5YYCODETYPE)fts5yyMajor;
+  fts5yytos->minor = *fts5yypMinor;
+  fts5yyTraceShift(fts5yypParser, fts5yyNewState);
+}
+
+/* The following table contains information about every rule that
+** is used during the reduce.
+*/
+static const struct {
+  fts5YYCODETYPE lhs;         /* Symbol on the left-hand side of the rule */
+  unsigned char nrhs;     /* Number of right-hand side symbols in the rule */
+} fts5yyRuleInfo[] = {
+  { 15, 1 },
+  { 16, 3 },
+  { 16, 3 },
+  { 16, 3 },
+  { 16, 3 },
+  { 16, 1 },
+  { 18, 1 },
+  { 18, 2 },
+  { 17, 1 },
+  { 17, 3 },
+  { 20, 3 },
+  { 20, 1 },
+  { 21, 2 },
+  { 21, 1 },
+  { 19, 1 },
+  { 19, 5 },
+  { 22, 1 },
+  { 22, 2 },
+  { 24, 0 },
+  { 24, 2 },
+  { 23, 4 },
+  { 23, 2 },
+  { 25, 1 },
+  { 25, 0 },
+};
+
+static void fts5yy_accept(fts5yyParser*);  /* Forward Declaration */
+
+/*
+** Perform a reduce action and the shift that must immediately
+** follow the reduce.
+*/
+static void fts5yy_reduce(
+  fts5yyParser *fts5yypParser,         /* The parser */
+  int fts5yyruleno                 /* Number of the rule by which to reduce */
+){
+  int fts5yygoto;                     /* The next state */
+  int fts5yyact;                      /* The next action */
+  fts5YYMINORTYPE fts5yygotominor;        /* The LHS of the rule reduced */
+  fts5yyStackEntry *fts5yymsp;            /* The top of the parser's stack */
+  int fts5yysize;                     /* Amount to pop the stack */
+  sqlite3Fts5ParserARG_FETCH;
+  fts5yymsp = &fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx];
+#ifndef NDEBUG
+  if( fts5yyTraceFILE && fts5yyruleno>=0 
+        && fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) ){
+    fts5yysize = fts5yyRuleInfo[fts5yyruleno].nrhs;
+    fprintf(fts5yyTraceFILE, "%sReduce [%s] -> state %d.\n", fts5yyTracePrompt,
+      fts5yyRuleName[fts5yyruleno], fts5yymsp[-fts5yysize].stateno);
+  }
+#endif /* NDEBUG */
+
+  /* Silence complaints from purify about fts5yygotominor being uninitialized
+  ** in some cases when it is copied into the stack after the following
+  ** switch.  fts5yygotominor is uninitialized when a rule reduces that does
+  ** not set the value of its left-hand side nonterminal.  Leaving the
+  ** value of the nonterminal uninitialized is utterly harmless as long
+  ** as the value is never used.  So really the only thing this code
+  ** accomplishes is to quieten purify.  
+  **
+  ** 2007-01-16:  The wireshark project (www.wireshark.org) reports that
+  ** without this code, their parser segfaults.  I'm not sure what there
+  ** parser is doing to make this happen.  This is the second bug report
+  ** from wireshark this week.  Clearly they are stressing Lemon in ways
+  ** that it has not been previously stressed...  (SQLite ticket #2172)
+  */
+  /*memset(&fts5yygotominor, 0, sizeof(fts5yygotominor));*/
+  fts5yygotominor = fts5yyzerominor;
+
+
+  switch( fts5yyruleno ){
+  /* Beginning here are the reduction cases.  A typical example
+  ** follows:
+  **   case 0:
+  **  #line <lineno> <grammarfile>
+  **     { ... }           // User supplied code
+  **  #line <lineno> <thisfile>
+  **     break;
+  */
+      case 0: /* input ::= expr */
+{ sqlite3Fts5ParseFinished(pParse, fts5yymsp[0].minor.fts5yy18); }
+        break;
+      case 1: /* expr ::= expr AND expr */
+{
+  fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-2].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0);
+}
+        break;
+      case 2: /* expr ::= expr OR expr */
+{
+  fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_OR, fts5yymsp[-2].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0);
+}
+        break;
+      case 3: /* expr ::= expr NOT expr */
+{
+  fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_NOT, fts5yymsp[-2].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0);
+}
+        break;
+      case 4: /* expr ::= LP expr RP */
+{fts5yygotominor.fts5yy18 = fts5yymsp[-1].minor.fts5yy18;}
+        break;
+      case 5: /* expr ::= exprlist */
+      case 6: /* exprlist ::= cnearset */ fts5yytestcase(fts5yyruleno==6);
+{fts5yygotominor.fts5yy18 = fts5yymsp[0].minor.fts5yy18;}
+        break;
+      case 7: /* exprlist ::= exprlist cnearset */
+{
+  fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-1].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0);
+}
+        break;
+      case 8: /* cnearset ::= nearset */
+{ 
+  fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy26); 
+}
+        break;
+      case 9: /* cnearset ::= colset COLON nearset */
+{ 
+  sqlite3Fts5ParseSetColset(pParse, fts5yymsp[0].minor.fts5yy26, fts5yymsp[-2].minor.fts5yy3);
+  fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy26); 
+}
+        break;
+      case 10: /* colset ::= LCP colsetlist RCP */
+{ fts5yygotominor.fts5yy3 = fts5yymsp[-1].minor.fts5yy3; }
+        break;
+      case 11: /* colset ::= STRING */
+{
+  fts5yygotominor.fts5yy3 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
+}
+        break;
+      case 12: /* colsetlist ::= colsetlist STRING */
+{ 
+  fts5yygotominor.fts5yy3 = sqlite3Fts5ParseColset(pParse, fts5yymsp[-1].minor.fts5yy3, &fts5yymsp[0].minor.fts5yy0); }
+        break;
+      case 13: /* colsetlist ::= STRING */
+{ 
+  fts5yygotominor.fts5yy3 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0); 
+}
+        break;
+      case 14: /* nearset ::= phrase */
+{ fts5yygotominor.fts5yy26 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11); }
+        break;
+      case 15: /* nearset ::= STRING LP nearphrases neardist_opt RP */
+{
+  sqlite3Fts5ParseNear(pParse, &fts5yymsp[-4].minor.fts5yy0);
+  sqlite3Fts5ParseSetDistance(pParse, fts5yymsp[-2].minor.fts5yy26, &fts5yymsp[-1].minor.fts5yy0);
+  fts5yygotominor.fts5yy26 = fts5yymsp[-2].minor.fts5yy26;
+}
+        break;
+      case 16: /* nearphrases ::= phrase */
+{ 
+  fts5yygotominor.fts5yy26 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11); 
+}
+        break;
+      case 17: /* nearphrases ::= nearphrases phrase */
+{
+  fts5yygotominor.fts5yy26 = sqlite3Fts5ParseNearset(pParse, fts5yymsp[-1].minor.fts5yy26, fts5yymsp[0].minor.fts5yy11);
+}
+        break;
+      case 18: /* neardist_opt ::= */
+{ fts5yygotominor.fts5yy0.p = 0; fts5yygotominor.fts5yy0.n = 0; }
+        break;
+      case 19: /* neardist_opt ::= COMMA STRING */
+{ fts5yygotominor.fts5yy0 = fts5yymsp[0].minor.fts5yy0; }
+        break;
+      case 20: /* phrase ::= phrase PLUS STRING star_opt */
+{ 
+  fts5yygotominor.fts5yy11 = sqlite3Fts5ParseTerm(pParse, fts5yymsp[-3].minor.fts5yy11, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy20);
+}
+        break;
+      case 21: /* phrase ::= STRING star_opt */
+{ 
+  fts5yygotominor.fts5yy11 = sqlite3Fts5ParseTerm(pParse, 0, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy20);
+}
+        break;
+      case 22: /* star_opt ::= STAR */
+{ fts5yygotominor.fts5yy20 = 1; }
+        break;
+      case 23: /* star_opt ::= */
+{ fts5yygotominor.fts5yy20 = 0; }
+        break;
+      default:
+        break;
+  };
+  assert( fts5yyruleno>=0 && fts5yyruleno<sizeof(fts5yyRuleInfo)/sizeof(fts5yyRuleInfo[0]) );
+  fts5yygoto = fts5yyRuleInfo[fts5yyruleno].lhs;
+  fts5yysize = fts5yyRuleInfo[fts5yyruleno].nrhs;
+  fts5yypParser->fts5yyidx -= fts5yysize;
+  fts5yyact = fts5yy_find_reduce_action(fts5yymsp[-fts5yysize].stateno,(fts5YYCODETYPE)fts5yygoto);
+  if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){
+    if( fts5yyact>fts5YY_MAX_SHIFT ) fts5yyact += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE;
+    /* If the reduce action popped at least
+    ** one element off the stack, then we can push the new element back
+    ** onto the stack here, and skip the stack overflow test in fts5yy_shift().
+    ** That gives a significant speed improvement. */
+    if( fts5yysize ){
+      fts5yypParser->fts5yyidx++;
+      fts5yymsp -= fts5yysize-1;
+      fts5yymsp->stateno = (fts5YYACTIONTYPE)fts5yyact;
+      fts5yymsp->major = (fts5YYCODETYPE)fts5yygoto;
+      fts5yymsp->minor = fts5yygotominor;
+      fts5yyTraceShift(fts5yypParser, fts5yyact);
+    }else{
+      fts5yy_shift(fts5yypParser,fts5yyact,fts5yygoto,&fts5yygotominor);
+    }
+  }else{
+    assert( fts5yyact == fts5YY_ACCEPT_ACTION );
+    fts5yy_accept(fts5yypParser);
+  }
+}
+
+/*
+** The following code executes when the parse fails
+*/
+#ifndef fts5YYNOERRORRECOVERY
+static void fts5yy_parse_failed(
+  fts5yyParser *fts5yypParser           /* The parser */
+){
+  sqlite3Fts5ParserARG_FETCH;
+#ifndef NDEBUG
+  if( fts5yyTraceFILE ){
+    fprintf(fts5yyTraceFILE,"%sFail!\n",fts5yyTracePrompt);
+  }
+#endif
+  while( fts5yypParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(fts5yypParser);
+  /* Here code is inserted which will be executed whenever the
+  ** parser fails */
+  sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+#endif /* fts5YYNOERRORRECOVERY */
+
+/*
+** The following code executes when a syntax error first occurs.
+*/
+static void fts5yy_syntax_error(
+  fts5yyParser *fts5yypParser,           /* The parser */
+  int fts5yymajor,                   /* The major type of the error token */
+  fts5YYMINORTYPE fts5yyminor            /* The minor type of the error token */
+){
+  sqlite3Fts5ParserARG_FETCH;
+#define FTS5TOKEN (fts5yyminor.fts5yy0)
+
+  sqlite3Fts5ParseError(
+    pParse, "fts5: syntax error near \"%.*s\"",FTS5TOKEN.n,FTS5TOKEN.p
+  );
+  sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/*
+** The following is executed when the parser accepts
+*/
+static void fts5yy_accept(
+  fts5yyParser *fts5yypParser           /* The parser */
+){
+  sqlite3Fts5ParserARG_FETCH;
+#ifndef NDEBUG
+  if( fts5yyTraceFILE ){
+    fprintf(fts5yyTraceFILE,"%sAccept!\n",fts5yyTracePrompt);
+  }
+#endif
+  while( fts5yypParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(fts5yypParser);
+  /* Here code is inserted which will be executed whenever the
+  ** parser accepts */
+  sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/* The main parser program.
+** The first argument is a pointer to a structure obtained from
+** "sqlite3Fts5ParserAlloc" which describes the current state of the parser.
+** The second argument is the major token number.  The third is
+** the minor token.  The fourth optional argument is whatever the
+** user wants (and specified in the grammar) and is available for
+** use by the action routines.
+**
+** Inputs:
+** <ul>
+** <li> A pointer to the parser (an opaque structure.)
+** <li> The major token number.
+** <li> The minor token number.
+** <li> An option argument of a grammar-specified type.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+static void sqlite3Fts5Parser(
+  void *fts5yyp,                   /* The parser */
+  int fts5yymajor,                 /* The major token code number */
+  sqlite3Fts5ParserFTS5TOKENTYPE fts5yyminor       /* The value for the token */
+  sqlite3Fts5ParserARG_PDECL               /* Optional %extra_argument parameter */
+){
+  fts5YYMINORTYPE fts5yyminorunion;
+  int fts5yyact;            /* The parser action. */
+#if !defined(fts5YYERRORSYMBOL) && !defined(fts5YYNOERRORRECOVERY)
+  int fts5yyendofinput;     /* True if we are at the end of input */
+#endif
+#ifdef fts5YYERRORSYMBOL
+  int fts5yyerrorhit = 0;   /* True if fts5yymajor has invoked an error */
+#endif
+  fts5yyParser *fts5yypParser;  /* The parser */
+
+  /* (re)initialize the parser, if necessary */
+  fts5yypParser = (fts5yyParser*)fts5yyp;
+  if( fts5yypParser->fts5yyidx<0 ){
+#if fts5YYSTACKDEPTH<=0
+    if( fts5yypParser->fts5yystksz <=0 ){
+      /*memset(&fts5yyminorunion, 0, sizeof(fts5yyminorunion));*/
+      fts5yyminorunion = fts5yyzerominor;
+      fts5yyStackOverflow(fts5yypParser, &fts5yyminorunion);
+      return;
+    }
+#endif
+    fts5yypParser->fts5yyidx = 0;
+    fts5yypParser->fts5yyerrcnt = -1;
+    fts5yypParser->fts5yystack[0].stateno = 0;
+    fts5yypParser->fts5yystack[0].major = 0;
+  }
+  fts5yyminorunion.fts5yy0 = fts5yyminor;
+#if !defined(fts5YYERRORSYMBOL) && !defined(fts5YYNOERRORRECOVERY)
+  fts5yyendofinput = (fts5yymajor==0);
+#endif
+  sqlite3Fts5ParserARG_STORE;
+
+#ifndef NDEBUG
+  if( fts5yyTraceFILE ){
+    fprintf(fts5yyTraceFILE,"%sInput %s\n",fts5yyTracePrompt,fts5yyTokenName[fts5yymajor]);
+  }
+#endif
+
+  do{
+    fts5yyact = fts5yy_find_shift_action(fts5yypParser,(fts5YYCODETYPE)fts5yymajor);
+    if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){
+      if( fts5yyact > fts5YY_MAX_SHIFT ) fts5yyact += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE;
+      fts5yy_shift(fts5yypParser,fts5yyact,fts5yymajor,&fts5yyminorunion);
+      fts5yypParser->fts5yyerrcnt--;
+      fts5yymajor = fts5YYNOCODE;
+    }else if( fts5yyact <= fts5YY_MAX_REDUCE ){
+      fts5yy_reduce(fts5yypParser,fts5yyact-fts5YY_MIN_REDUCE);
+    }else{
+      assert( fts5yyact == fts5YY_ERROR_ACTION );
+#ifdef fts5YYERRORSYMBOL
+      int fts5yymx;
+#endif
+#ifndef NDEBUG
+      if( fts5yyTraceFILE ){
+        fprintf(fts5yyTraceFILE,"%sSyntax Error!\n",fts5yyTracePrompt);
+      }
+#endif
+#ifdef fts5YYERRORSYMBOL
+      /* A syntax error has occurred.
+      ** The response to an error depends upon whether or not the
+      ** grammar defines an error token "ERROR".  
+      **
+      ** This is what we do if the grammar does define ERROR:
+      **
+      **  * Call the %syntax_error function.
+      **
+      **  * Begin popping the stack until we enter a state where
+      **    it is legal to shift the error symbol, then shift
+      **    the error symbol.
+      **
+      **  * Set the error count to three.
+      **
+      **  * Begin accepting and shifting new tokens.  No new error
+      **    processing will occur until three tokens have been
+      **    shifted successfully.
+      **
+      */
+      if( fts5yypParser->fts5yyerrcnt<0 ){
+        fts5yy_syntax_error(fts5yypParser,fts5yymajor,fts5yyminorunion);
+      }
+      fts5yymx = fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx].major;
+      if( fts5yymx==fts5YYERRORSYMBOL || fts5yyerrorhit ){
+#ifndef NDEBUG
+        if( fts5yyTraceFILE ){
+          fprintf(fts5yyTraceFILE,"%sDiscard input token %s\n",
+             fts5yyTracePrompt,fts5yyTokenName[fts5yymajor]);
+        }
+#endif
+        fts5yy_destructor(fts5yypParser, (fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
+        fts5yymajor = fts5YYNOCODE;
+      }else{
+         while(
+          fts5yypParser->fts5yyidx >= 0 &&
+          fts5yymx != fts5YYERRORSYMBOL &&
+          (fts5yyact = fts5yy_find_reduce_action(
+                        fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx].stateno,
+                        fts5YYERRORSYMBOL)) >= fts5YY_MIN_REDUCE
+        ){
+          fts5yy_pop_parser_stack(fts5yypParser);
+        }
+        if( fts5yypParser->fts5yyidx < 0 || fts5yymajor==0 ){
+          fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
+          fts5yy_parse_failed(fts5yypParser);
+          fts5yymajor = fts5YYNOCODE;
+        }else if( fts5yymx!=fts5YYERRORSYMBOL ){
+          fts5YYMINORTYPE u2;
+          u2.fts5YYERRSYMDT = 0;
+          fts5yy_shift(fts5yypParser,fts5yyact,fts5YYERRORSYMBOL,&u2);
+        }
+      }
+      fts5yypParser->fts5yyerrcnt = 3;
+      fts5yyerrorhit = 1;
+#elif defined(fts5YYNOERRORRECOVERY)
+      /* If the fts5YYNOERRORRECOVERY macro is defined, then do not attempt to
+      ** do any kind of error recovery.  Instead, simply invoke the syntax
+      ** error routine and continue going as if nothing had happened.
+      **
+      ** Applications can set this macro (for example inside %include) if
+      ** they intend to abandon the parse upon the first syntax error seen.
+      */
+      fts5yy_syntax_error(fts5yypParser,fts5yymajor,fts5yyminorunion);
+      fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
+      fts5yymajor = fts5YYNOCODE;
+      
+#else  /* fts5YYERRORSYMBOL is not defined */
+      /* This is what we do if the grammar does not define ERROR:
+      **
+      **  * Report an error message, and throw away the input token.
+      **
+      **  * If the input token is $, then fail the parse.
+      **
+      ** As before, subsequent error messages are suppressed until
+      ** three input tokens have been successfully shifted.
+      */
+      if( fts5yypParser->fts5yyerrcnt<=0 ){
+        fts5yy_syntax_error(fts5yypParser,fts5yymajor,fts5yyminorunion);
+      }
+      fts5yypParser->fts5yyerrcnt = 3;
+      fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
+      if( fts5yyendofinput ){
+        fts5yy_parse_failed(fts5yypParser);
+      }
+      fts5yymajor = fts5YYNOCODE;
+#endif
+    }
+  }while( fts5yymajor!=fts5YYNOCODE && fts5yypParser->fts5yyidx>=0 );
+#ifndef NDEBUG
+  if( fts5yyTraceFILE ){
+    fprintf(fts5yyTraceFILE,"%sReturn\n",fts5yyTracePrompt);
+  }
+#endif
+  return;
+}
+
+/*
+** 2014 May 31
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+******************************************************************************
+*/
+
+
+#include <math.h>                 /* amalgamator: keep */
+
+/*
+** Object used to iterate through all "coalesced phrase instances" in 
+** a single column of the current row. If the phrase instances in the
+** column being considered do not overlap, this object simply iterates
+** through them. Or, if they do overlap (share one or more tokens in
+** common), each set of overlapping instances is treated as a single
+** match. See documentation for the highlight() auxiliary function for
+** details.
+**
+** Usage is:
+**
+**   for(rc = fts5CInstIterNext(pApi, pFts, iCol, &iter);
+**      (rc==SQLITE_OK && 0==fts5CInstIterEof(&iter);
+**      rc = fts5CInstIterNext(&iter)
+**   ){
+**     printf("instance starts at %d, ends at %d\n", iter.iStart, iter.iEnd);
+**   }
+**
+*/
+typedef struct CInstIter CInstIter;
+struct CInstIter {
+  const Fts5ExtensionApi *pApi;   /* API offered by current FTS version */
+  Fts5Context *pFts;              /* First arg to pass to pApi functions */
+  int iCol;                       /* Column to search */
+  int iInst;                      /* Next phrase instance index */
+  int nInst;                      /* Total number of phrase instances */
+
+  /* Output variables */
+  int iStart;                     /* First token in coalesced phrase instance */
+  int iEnd;                       /* Last token in coalesced phrase instance */
+};
+
+/*
+** Advance the iterator to the next coalesced phrase instance. Return
+** an SQLite error code if an error occurs, or SQLITE_OK otherwise.
+*/
+static int fts5CInstIterNext(CInstIter *pIter){
+  int rc = SQLITE_OK;
+  pIter->iStart = -1;
+  pIter->iEnd = -1;
+
+  while( rc==SQLITE_OK && pIter->iInst<pIter->nInst ){
+    int ip; int ic; int io;
+    rc = pIter->pApi->xInst(pIter->pFts, pIter->iInst, &ip, &ic, &io);
+    if( rc==SQLITE_OK ){
+      if( ic==pIter->iCol ){
+        int iEnd = io - 1 + pIter->pApi->xPhraseSize(pIter->pFts, ip);
+        if( pIter->iStart<0 ){
+          pIter->iStart = io;
+          pIter->iEnd = iEnd;
+        }else if( io<=pIter->iEnd ){
+          if( iEnd>pIter->iEnd ) pIter->iEnd = iEnd;
+        }else{
+          break;
+        }
+      }
+      pIter->iInst++;
+    }
+  }
+
+  return rc;
+}
+
+/*
+** Initialize the iterator object indicated by the final parameter to 
+** iterate through coalesced phrase instances in column iCol.
+*/
+static int fts5CInstIterInit(
+  const Fts5ExtensionApi *pApi,
+  Fts5Context *pFts,
+  int iCol,
+  CInstIter *pIter
+){
+  int rc;
+
+  memset(pIter, 0, sizeof(CInstIter));
+  pIter->pApi = pApi;
+  pIter->pFts = pFts;
+  pIter->iCol = iCol;
+  rc = pApi->xInstCount(pFts, &pIter->nInst);
+
+  if( rc==SQLITE_OK ){
+    rc = fts5CInstIterNext(pIter);
+  }
+
+  return rc;
+}
+
+
+
+/*************************************************************************
+** Start of highlight() implementation.
+*/
+typedef struct HighlightContext HighlightContext;
+struct HighlightContext {
+  CInstIter iter;                 /* Coalesced Instance Iterator */
+  int iPos;                       /* Current token offset in zIn[] */
+  int iRangeStart;                /* First token to include */
+  int iRangeEnd;                  /* If non-zero, last token to include */
+  const char *zOpen;              /* Opening highlight */
+  const char *zClose;             /* Closing highlight */
+  const char *zIn;                /* Input text */
+  int nIn;                        /* Size of input text in bytes */
+  int iOff;                       /* Current offset within zIn[] */
+  char *zOut;                     /* Output value */
+};
+
+/*
+** Append text to the HighlightContext output string - p->zOut. Argument
+** z points to a buffer containing n bytes of text to append. If n is 
+** negative, everything up until the first '\0' is appended to the output.
+**
+** If *pRc is set to any value other than SQLITE_OK when this function is 
+** called, it is a no-op. If an error (i.e. an OOM condition) is encountered, 
+** *pRc is set to an error code before returning. 
+*/
+static void fts5HighlightAppend(
+  int *pRc, 
+  HighlightContext *p, 
+  const char *z, int n
+){
+  if( *pRc==SQLITE_OK ){
+    if( n<0 ) n = strlen(z);
+    p->zOut = sqlite3_mprintf("%z%.*s", p->zOut, n, z);
+    if( p->zOut==0 ) *pRc = SQLITE_NOMEM;
+  }
+}
+
+/*
+** Tokenizer callback used by implementation of highlight() function.
+*/
+static int fts5HighlightCb(
+  void *pContext,                 /* Pointer to HighlightContext object */
+  int tflags,                     /* Mask of FTS5_TOKEN_* flags */
+  const char *pToken,             /* Buffer containing token */
+  int nToken,                     /* Size of token in bytes */
+  int iStartOff,                  /* Start offset of token */
+  int iEndOff                     /* End offset of token */
+){
+  HighlightContext *p = (HighlightContext*)pContext;
+  int rc = SQLITE_OK;
+  int iPos;
+
+  if( tflags & FTS5_TOKEN_COLOCATED ) return SQLITE_OK;
+  iPos = p->iPos++;
+
+  if( p->iRangeEnd>0 ){
+    if( iPos<p->iRangeStart || iPos>p->iRangeEnd ) return SQLITE_OK;
+    if( p->iRangeStart && iPos==p->iRangeStart ) p->iOff = iStartOff;
+  }
+
+  if( iPos==p->iter.iStart ){
+    fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iStartOff - p->iOff);
+    fts5HighlightAppend(&rc, p, p->zOpen, -1);
+    p->iOff = iStartOff;
+  }
+
+  if( iPos==p->iter.iEnd ){
+    if( p->iRangeEnd && p->iter.iStart<p->iRangeStart ){
+      fts5HighlightAppend(&rc, p, p->zOpen, -1);
+    }
+    fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
+    fts5HighlightAppend(&rc, p, p->zClose, -1);
+    p->iOff = iEndOff;
+    if( rc==SQLITE_OK ){
+      rc = fts5CInstIterNext(&p->iter);
+    }
+  }
+
+  if( p->iRangeEnd>0 && iPos==p->iRangeEnd ){
+    fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
+    p->iOff = iEndOff;
+    if( iPos<p->iter.iEnd ){
+      fts5HighlightAppend(&rc, p, p->zClose, -1);
+    }
+  }
+
+  return rc;
+}
+
+/*
+** Implementation of highlight() function.
+*/
+static void fts5HighlightFunction(
+  const Fts5ExtensionApi *pApi,   /* API offered by current FTS version */
+  Fts5Context *pFts,              /* First arg to pass to pApi functions */
+  sqlite3_context *pCtx,          /* Context for returning result/error */
+  int nVal,                       /* Number of values in apVal[] array */
+  sqlite3_value **apVal           /* Array of trailing arguments */
+){
+  HighlightContext ctx;
+  int rc;
+  int iCol;
+
+  if( nVal!=3 ){
+    const char *zErr = "wrong number of arguments to function highlight()";
+    sqlite3_result_error(pCtx, zErr, -1);
+    return;
+  }
+
+  iCol = sqlite3_value_int(apVal[0]);
+  memset(&ctx, 0, sizeof(HighlightContext));
+  ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]);
+  ctx.zClose = (const char*)sqlite3_value_text(apVal[2]);
+  rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn);
+
+  if( ctx.zIn ){
+    if( rc==SQLITE_OK ){
+      rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter);
+    }
+
+    if( rc==SQLITE_OK ){
+      rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
+    }
+    fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff);
+
+    if( rc==SQLITE_OK ){
+      sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT);
+    }
+    sqlite3_free(ctx.zOut);
+  }
+  if( rc!=SQLITE_OK ){
+    sqlite3_result_error_code(pCtx, rc);
+  }
+}
+/*
+** End of highlight() implementation.
+**************************************************************************/
+
+/*
+** Implementation of snippet() function.
+*/
+static void fts5SnippetFunction(
+  const Fts5ExtensionApi *pApi,   /* API offered by current FTS version */
+  Fts5Context *pFts,              /* First arg to pass to pApi functions */
+  sqlite3_context *pCtx,          /* Context for returning result/error */
+  int nVal,                       /* Number of values in apVal[] array */
+  sqlite3_value **apVal           /* Array of trailing arguments */
+){
+  HighlightContext ctx;
+  int rc = SQLITE_OK;             /* Return code */
+  int iCol;                       /* 1st argument to snippet() */
+  const char *zEllips;            /* 4th argument to snippet() */
+  int nToken;                     /* 5th argument to snippet() */
+  int nInst = 0;                  /* Number of instance matches this row */
+  int i;                          /* Used to iterate through instances */
+  int nPhrase;                    /* Number of phrases in query */
+  unsigned char *aSeen;           /* Array of "seen instance" flags */
+  int iBestCol;                   /* Column containing best snippet */
+  int iBestStart = 0;             /* First token of best snippet */
+  int iBestLast;                  /* Last token of best snippet */
+  int nBestScore = 0;             /* Score of best snippet */
+  int nColSize = 0;               /* Total size of iBestCol in tokens */
+
+  if( nVal!=5 ){
+    const char *zErr = "wrong number of arguments to function snippet()";
+    sqlite3_result_error(pCtx, zErr, -1);
+    return;
+  }
+
+  memset(&ctx, 0, sizeof(HighlightContext));
+  iCol = sqlite3_value_int(apVal[0]);
+  ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]);
+  ctx.zClose = (const char*)sqlite3_value_text(apVal[2]);
+  zEllips = (const char*)sqlite3_value_text(apVal[3]);
+  nToken = sqlite3_value_int(apVal[4]);
+  iBestLast = nToken-1;
+
+  iBestCol = (iCol>=0 ? iCol : 0);
+  nPhrase = pApi->xPhraseCount(pFts);
+  aSeen = sqlite3_malloc(nPhrase);
+  if( aSeen==0 ){
+    rc = SQLITE_NOMEM;
+  }
+
+  if( rc==SQLITE_OK ){
+    rc = pApi->xInstCount(pFts, &nInst);
+  }
+  for(i=0; rc==SQLITE_OK && i<nInst; i++){
+    int ip, iSnippetCol, iStart;
+    memset(aSeen, 0, nPhrase);
+    rc = pApi->xInst(pFts, i, &ip, &iSnippetCol, &iStart);
+    if( rc==SQLITE_OK && (iCol<0 || iSnippetCol==iCol) ){
+      int nScore = 1000;
+      int iLast = iStart - 1 + pApi->xPhraseSize(pFts, ip);
+      int j;
+      aSeen[ip] = 1;
+
+      for(j=i+1; rc==SQLITE_OK && j<nInst; j++){
+        int ic; int io; int iFinal;
+        rc = pApi->xInst(pFts, j, &ip, &ic, &io);
+        iFinal = io + pApi->xPhraseSize(pFts, ip) - 1;
+        if( rc==SQLITE_OK && ic==iSnippetCol && iLast<iStart+nToken ){
+          nScore += aSeen[ip] ? 1000 : 1;
+          aSeen[ip] = 1;
+          if( iFinal>iLast ) iLast = iFinal;
+        }
+      }
+
+      if( rc==SQLITE_OK && nScore>nBestScore ){
+        iBestCol = iSnippetCol;
+        iBestStart = iStart;
+        iBestLast = iLast;
+        nBestScore = nScore;
+      }
+    }
+  }
+
+  if( rc==SQLITE_OK ){
+    rc = pApi->xColumnSize(pFts, iBestCol, &nColSize);
+  }
+  if( rc==SQLITE_OK ){
+    rc = pApi->xColumnText(pFts, iBestCol, &ctx.zIn, &ctx.nIn);
+  }
+  if( ctx.zIn ){
+    if( rc==SQLITE_OK ){
+      rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter);
+    }
+
+    if( (iBestStart+nToken-1)>iBestLast ){
+      iBestStart -= (iBestStart+nToken-1-iBestLast) / 2;
+    }
+    if( iBestStart+nToken>nColSize ){
+      iBestStart = nColSize - nToken;
+    }
+    if( iBestStart<0 ) iBestStart = 0;
+
+    ctx.iRangeStart = iBestStart;
+    ctx.iRangeEnd = iBestStart + nToken - 1;
+
+    if( iBestStart>0 ){
+      fts5HighlightAppend(&rc, &ctx, zEllips, -1);
+    }
+    if( rc==SQLITE_OK ){
+      rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
+    }
+    if( ctx.iRangeEnd>=(nColSize-1) ){
+      fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff);
+    }else{
+      fts5HighlightAppend(&rc, &ctx, zEllips, -1);
+    }
+
+    if( rc==SQLITE_OK ){
+      sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT);
+    }else{
+      sqlite3_result_error_code(pCtx, rc);
+    }
+    sqlite3_free(ctx.zOut);
+  }
+  sqlite3_free(aSeen);
+}
+
+/************************************************************************/
+
+/*
+** The first time the bm25() function is called for a query, an instance
+** of the following structure is allocated and populated.
+*/
+typedef struct Fts5Bm25Data Fts5Bm25Data;
+struct Fts5Bm25Data {
+  int nPhrase;                    /* Number of phrases in query */
+  double avgdl;                   /* Average number of tokens in each row */
+  double *aIDF;                   /* IDF for each phrase */
+  double *aFreq;                  /* Array used to calculate phrase freq. */
+};
+
+/*
+** Callback used by fts5Bm25GetData() to count the number of rows in the
+** table matched by each individual phrase within the query.
+*/
+static int fts5CountCb(
+  const Fts5ExtensionApi *pApi, 
+  Fts5Context *pFts,
+  void *pUserData                 /* Pointer to sqlite3_int64 variable */
+){
+  sqlite3_int64 *pn = (sqlite3_int64*)pUserData;
+  (*pn)++;
+  return SQLITE_OK;
+}
+
+/*
+** Set *ppData to point to the Fts5Bm25Data object for the current query. 
+** If the object has not already been allocated, allocate and populate it
+** now.
+*/
+static int fts5Bm25GetData(
+  const Fts5ExtensionApi *pApi, 
+  Fts5Context *pFts,
+  Fts5Bm25Data **ppData           /* OUT: bm25-data object for this query */
+){
+  int rc = SQLITE_OK;             /* Return code */
+  Fts5Bm25Data *p;                /* Object to return */
+
+  p = pApi->xGetAuxdata(pFts, 0);
+  if( p==0 ){
+    int nPhrase;                  /* Number of phrases in query */
+    sqlite3_int64 nRow = 0;       /* Number of rows in table */
+    sqlite3_int64 nToken = 0;     /* Number of tokens in table */
+    int nByte;                    /* Bytes of space to allocate */
+    int i;
+
+    /* Allocate the Fts5Bm25Data object */
+    nPhrase = pApi->xPhraseCount(pFts);
+    nByte = sizeof(Fts5Bm25Data) + nPhrase*2*sizeof(double);
+    p = (Fts5Bm25Data*)sqlite3_malloc(nByte);
+    if( p==0 ){
+      rc = SQLITE_NOMEM;
+    }else{
+      memset(p, 0, nByte);
+      p->nPhrase = nPhrase;
+      p->aIDF = (double*)&p[1];
+      p->aFreq = &p->aIDF[nPhrase];
+    }
+
+    /* Calculate the average document length for this FTS5 table */
+    if( rc==SQLITE_OK ) rc = pApi->xRowCount(pFts, &nRow);
+    if( rc==SQLITE_OK ) rc = pApi->xColumnTotalSize(pFts, -1, &nToken);
+    if( rc==SQLITE_OK ) p->avgdl = (double)nToken  / (double)nRow;
+
+    /* Calculate an IDF for each phrase in the query */
+    for(i=0; rc==SQLITE_OK && i<nPhrase; i++){
+      sqlite3_int64 nHit = 0;
+      rc = pApi->xQueryPhrase(pFts, i, (void*)&nHit, fts5CountCb);
+      if( rc==SQLITE_OK ){
+        /* Calculate the IDF (Inverse Document Frequency) for phrase i.
+        ** This is done using the standard BM25 formula as found on wikipedia:
+        **
+        **   IDF = log( (N - nHit + 0.5) / (nHit + 0.5) )
+        **
+        ** where "N" is the total number of documents in the set and nHit
+        ** is the number that contain at least one instance of the phrase
+        ** under consideration.
+        **
+        ** The problem with this is that if (N < 2*nHit), the IDF is 
+        ** negative. Which is undesirable. So the mimimum allowable IDF is
+        ** (1e-6) - roughly the same as a term that appears in just over
+        ** half of set of 5,000,000 documents.  */
+        double idf = log( (nRow - nHit + 0.5) / (nHit + 0.5) );
+        if( idf<=0.0 ) idf = 1e-6;
+        p->aIDF[i] = idf;
+      }
+    }
+
+    if( rc!=SQLITE_OK ){
+      sqlite3_free(p);
+    }else{
+      rc = pApi->xSetAuxdata(pFts, p, sqlite3_free);
+    }
+    if( rc!=SQLITE_OK ) p = 0;
+  }
+  *ppData = p;
+  return rc;
+}
+
+/*
+** Implementation of bm25() function.
+*/
+static void fts5Bm25Function(
+  const Fts5ExtensionApi *pApi,   /* API offered by current FTS version */
+  Fts5Context *pFts,              /* First arg to pass to pApi functions */
+  sqlite3_context *pCtx,          /* Context for returning result/error */
+  int nVal,                       /* Number of values in apVal[] array */
+  sqlite3_value **apVal           /* Array of trailing arguments */
+){
+  const double k1 = 1.2;          /* Constant "k1" from BM25 formula */
+  const double b = 0.75;          /* Constant "b" from BM25 formula */
+  int rc = SQLITE_OK;             /* Error code */
+  double score = 0.0;             /* SQL function return value */
+  Fts5Bm25Data *pData;            /* Values allocated/calculated once only */
+  int i;                          /* Iterator variable */
+  int nInst = 0;                  /* Value returned by xInstCount() */
+  double D = 0.0;                 /* Total number of tokens in row */
+  double *aFreq = 0;              /* Array of phrase freq. for current row */
+
+  /* Calculate the phrase frequency (symbol "f(qi,D)" in the documentation)
+  ** for each phrase in the query for the current row. */
+  rc = fts5Bm25GetData(pApi, pFts, &pData);
+  if( rc==SQLITE_OK ){
+    aFreq = pData->aFreq;
+    memset(aFreq, 0, sizeof(double) * pData->nPhrase);
+    rc = pApi->xInstCount(pFts, &nInst);
+  }
+  for(i=0; rc==SQLITE_OK && i<nInst; i++){
+    int ip; int ic; int io;
+    rc = pApi->xInst(pFts, i, &ip, &ic, &io);
+    if( rc==SQLITE_OK ){
+      double w = (nVal > ic) ? sqlite3_value_double(apVal[ic]) : 1.0;
+      aFreq[ip] += w;
+    }
+  }
+
+  /* Figure out the total size of the current row in tokens. */
+  if( rc==SQLITE_OK ){
+    int nTok;
+    rc = pApi->xColumnSize(pFts, -1, &nTok);
+    D = (double)nTok;
+  }
+
+  /* Determine the BM25 score for the current row. */
+  for(i=0; rc==SQLITE_OK && i<pData->nPhrase; i++){
+    score += pData->aIDF[i] * (
+      ( aFreq[i] * (k1 + 1.0) ) / 
+      ( aFreq[i] + k1 * (1 - b + b * D / pData->avgdl) )
+    );
+  }
+  
+  /* If no error has occurred, return the calculated score. Otherwise,
+  ** throw an SQL exception.  */
+  if( rc==SQLITE_OK ){
+    sqlite3_result_double(pCtx, -1.0 * score);
+  }else{
+    sqlite3_result_error_code(pCtx, rc);
+  }
+}
+
+static int sqlite3Fts5AuxInit(fts5_api *pApi){
+  struct Builtin {
+    const char *zFunc;            /* Function name (nul-terminated) */
+    void *pUserData;              /* User-data pointer */
+    fts5_extension_function xFunc;/* Callback function */
+    void (*xDestroy)(void*);      /* Destructor function */
+  } aBuiltin [] = {
+    { "snippet",   0, fts5SnippetFunction, 0 },
+    { "highlight", 0, fts5HighlightFunction, 0 },
+    { "bm25",      0, fts5Bm25Function,    0 },
+  };
+  int rc = SQLITE_OK;             /* Return code */
+  int i;                          /* To iterate through builtin functions */
+
+  for(i=0; rc==SQLITE_OK && i<sizeof(aBuiltin)/sizeof(aBuiltin[0]); i++){
+    rc = pApi->xCreateFunction(pApi,
+        aBuiltin[i].zFunc,
+        aBuiltin[i].pUserData,
+        aBuiltin[i].xFunc,
+        aBuiltin[i].xDestroy
+    );
+  }
+
+  return rc;
+}
+
+
+
+/*
+** 2014 May 31
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+******************************************************************************
+*/
+
+
+
+
+static int sqlite3Fts5BufferGrow(int *pRc, Fts5Buffer *pBuf, int nByte){
+
+  if( (pBuf->n + nByte) > pBuf->nSpace ){
+    u8 *pNew;
+    int nNew = pBuf->nSpace ? pBuf->nSpace*2 : 64;
+
+    /* A no-op if an error has already occurred */
+    if( *pRc ) return 1;
+
+    while( nNew<(pBuf->n + nByte) ){
+      nNew = nNew * 2;
+    }
+    pNew = sqlite3_realloc(pBuf->p, nNew);
+    if( pNew==0 ){
+      *pRc = SQLITE_NOMEM;
+      return 1;
+    }else{
+      pBuf->nSpace = nNew;
+      pBuf->p = pNew;
+    }
+  }
+  return 0;
+}
+
+/*
+** Encode value iVal as an SQLite varint and append it to the buffer object
+** pBuf. If an OOM error occurs, set the error code in p.
+*/
+static void sqlite3Fts5BufferAppendVarint(int *pRc, Fts5Buffer *pBuf, i64 iVal){
+  if( sqlite3Fts5BufferGrow(pRc, pBuf, 9) ) return;
+  pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iVal);
+}
+
+static void sqlite3Fts5Put32(u8 *aBuf, int iVal){
+  aBuf[0] = (iVal>>24) & 0x00FF;
+  aBuf[1] = (iVal>>16) & 0x00FF;
+  aBuf[2] = (iVal>> 8) & 0x00FF;
+  aBuf[3] = (iVal>> 0) & 0x00FF;
+}
+
+static int sqlite3Fts5Get32(const u8 *aBuf){
+  return (aBuf[0] << 24) + (aBuf[1] << 16) + (aBuf[2] << 8) + aBuf[3];
+}
+
+static void sqlite3Fts5BufferAppend32(int *pRc, Fts5Buffer *pBuf, int iVal){
+  if( sqlite3Fts5BufferGrow(pRc, pBuf, 4) ) return;
+  sqlite3Fts5Put32(&pBuf->p[pBuf->n], iVal);
+  pBuf->n += 4;
+}
+
+/*
+** Append buffer nData/pData to buffer pBuf. If an OOM error occurs, set 
+** the error code in p. If an error has already occurred when this function
+** is called, it is a no-op.
+*/
+static void sqlite3Fts5BufferAppendBlob(
+  int *pRc,
+  Fts5Buffer *pBuf, 
+  int nData, 
+  const u8 *pData
+){
+  assert( *pRc || nData>=0 );
+  if( sqlite3Fts5BufferGrow(pRc, pBuf, nData) ) return;
+  memcpy(&pBuf->p[pBuf->n], pData, nData);
+  pBuf->n += nData;
+}
+
+/*
+** Append the nul-terminated string zStr to the buffer pBuf. This function
+** ensures that the byte following the buffer data is set to 0x00, even 
+** though this byte is not included in the pBuf->n count.
+*/
+static void sqlite3Fts5BufferAppendString(
+  int *pRc,
+  Fts5Buffer *pBuf, 
+  const char *zStr
+){
+  int nStr = strlen(zStr);
+  sqlite3Fts5BufferAppendBlob(pRc, pBuf, nStr+1, (const u8*)zStr);
+  pBuf->n--;
+}
+
+/*
+** Argument zFmt is a printf() style format string. This function performs
+** the printf() style processing, then appends the results to buffer pBuf.
+**
+** Like sqlite3Fts5BufferAppendString(), this function ensures that the byte 
+** following the buffer data is set to 0x00, even though this byte is not
+** included in the pBuf->n count.
+*/ 
+static void sqlite3Fts5BufferAppendPrintf(
+  int *pRc,
+  Fts5Buffer *pBuf, 
+  char *zFmt, ...
+){
+  if( *pRc==SQLITE_OK ){
+    char *zTmp;
+    va_list ap;
+    va_start(ap, zFmt);
+    zTmp = sqlite3_vmprintf(zFmt, ap);
+    va_end(ap);
+
+    if( zTmp==0 ){
+      *pRc = SQLITE_NOMEM;
+    }else{
+      sqlite3Fts5BufferAppendString(pRc, pBuf, zTmp);
+      sqlite3_free(zTmp);
+    }
+  }
+}
+
+static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...){
+  char *zRet = 0;
+  if( *pRc==SQLITE_OK ){
+    va_list ap;
+    va_start(ap, zFmt);
+    zRet = sqlite3_vmprintf(zFmt, ap);
+    va_end(ap);
+    if( zRet==0 ){
+      *pRc = SQLITE_NOMEM; 
+    }
+  }
+  return zRet;
+}
+
+/*
+** Free any buffer allocated by pBuf. Zero the structure before returning.
+*/
+static void sqlite3Fts5BufferFree(Fts5Buffer *pBuf){
+  sqlite3_free(pBuf->p);
+  memset(pBuf, 0, sizeof(Fts5Buffer));
+}
+
+/*
+** Zero the contents of the buffer object. But do not free the associated 
+** memory allocation.
+*/
+static void sqlite3Fts5BufferZero(Fts5Buffer *pBuf){
+  pBuf->n = 0;
+}
+
+/*
+** Set the buffer to contain nData/pData. If an OOM error occurs, leave an
+** the error code in p. If an error has already occurred when this function
+** is called, it is a no-op.
+*/
+static void sqlite3Fts5BufferSet(
+  int *pRc,
+  Fts5Buffer *pBuf, 
+  int nData, 
+  const u8 *pData
+){
+  pBuf->n = 0;
+  sqlite3Fts5BufferAppendBlob(pRc, pBuf, nData, pData);
+}
+
+static int sqlite3Fts5PoslistNext64(
+  const u8 *a, int n,             /* Buffer containing poslist */
+  int *pi,                        /* IN/OUT: Offset within a[] */
+  i64 *piOff                      /* IN/OUT: Current offset */
+){
+  int i = *pi;
+  if( i>=n ){
+    /* EOF */
+    *piOff = -1;
+    return 1;  
+  }else{
+    i64 iOff = *piOff;
+    int iVal;
+    fts5FastGetVarint32(a, i, iVal);
+    if( iVal==1 ){
+      fts5FastGetVarint32(a, i, iVal);
+      iOff = ((i64)iVal) << 32;
+      fts5FastGetVarint32(a, i, iVal);
+    }
+    *piOff = iOff + (iVal-2);
+    *pi = i;
+    return 0;
+  }
+}
+
+
+/*
+** Advance the iterator object passed as the only argument. Return true
+** if the iterator reaches EOF, or false otherwise.
+*/
+static int sqlite3Fts5PoslistReaderNext(Fts5PoslistReader *pIter){
+  if( sqlite3Fts5PoslistNext64(pIter->a, pIter->n, &pIter->i, &pIter->iPos) ){
+    pIter->bEof = 1;
+  }
+  return pIter->bEof;
+}
+
+static int sqlite3Fts5PoslistReaderInit(
+  const u8 *a, int n,             /* Poslist buffer to iterate through */
+  Fts5PoslistReader *pIter        /* Iterator object to initialize */
+){
+  memset(pIter, 0, sizeof(*pIter));
+  pIter->a = a;
+  pIter->n = n;
+  sqlite3Fts5PoslistReaderNext(pIter);
+  return pIter->bEof;
+}
+
+static int sqlite3Fts5PoslistWriterAppend(
+  Fts5Buffer *pBuf, 
+  Fts5PoslistWriter *pWriter,
+  i64 iPos
+){
+  static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32;
+  int rc = SQLITE_OK;
+  if( 0==sqlite3Fts5BufferGrow(&rc, pBuf, 5+5+5) ){
+    if( (iPos & colmask) != (pWriter->iPrev & colmask) ){
+      pBuf->p[pBuf->n++] = 1;
+      pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32));
+      pWriter->iPrev = (iPos & colmask);
+    }
+    pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-pWriter->iPrev)+2);
+    pWriter->iPrev = iPos;
+  }
+  return rc;
+}
+
+static void *sqlite3Fts5MallocZero(int *pRc, int nByte){
+  void *pRet = 0;
+  if( *pRc==SQLITE_OK ){
+    pRet = sqlite3_malloc(nByte);
+    if( pRet==0 && nByte>0 ){
+      *pRc = SQLITE_NOMEM;
+    }else{
+      memset(pRet, 0, nByte);
+    }
+  }
+  return pRet;
+}
+
+/*
+** Return a nul-terminated copy of the string indicated by pIn. If nIn
+** is non-negative, then it is the length of the string in bytes. Otherwise,
+** the length of the string is determined using strlen().
+**
+** It is the responsibility of the caller to eventually free the returned
+** buffer using sqlite3_free(). If an OOM error occurs, NULL is returned. 
+*/
+static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn){
+  char *zRet = 0;
+  if( *pRc==SQLITE_OK ){
+    if( nIn<0 ){
+      nIn = strlen(pIn);
+    }
+    zRet = (char*)sqlite3_malloc(nIn+1);
+    if( zRet ){
+      memcpy(zRet, pIn, nIn);
+      zRet[nIn] = '\0';
+    }else{
+      *pRc = SQLITE_NOMEM;
+    }
+  }
+  return zRet;
+}
+
+
+/*
+** Return true if character 't' may be part of an FTS5 bareword, or false
+** otherwise. Characters that may be part of barewords:
+**
+**   * All non-ASCII characters,
+**   * The 52 upper and lower case ASCII characters, and
+**   * The 10 integer ASCII characters.
+**   * The underscore character "_" (0x5F).
+**   * The unicode "subsitute" character (0x1A).
+*/
+static int sqlite3Fts5IsBareword(char t){
+  u8 aBareword[128] = {
+    0, 0, 0, 0, 0, 0, 0, 0,    0, 0, 0, 0, 0, 0, 0, 0,   /* 0x00 .. 0x0F */
+    0, 0, 0, 0, 0, 0, 0, 0,    0, 0, 1, 0, 0, 0, 0, 0,   /* 0x10 .. 0x1F */
+    0, 0, 0, 0, 0, 0, 0, 0,    0, 0, 0, 0, 0, 0, 0, 0,   /* 0x20 .. 0x2F */
+    1, 1, 1, 1, 1, 1, 1, 1,    1, 1, 0, 0, 0, 0, 0, 0,   /* 0x30 .. 0x3F */
+    0, 1, 1, 1, 1, 1, 1, 1,    1, 1, 1, 1, 1, 1, 1, 1,   /* 0x40 .. 0x4F */
+    1, 1, 1, 1, 1, 1, 1, 1,    1, 1, 1, 0, 0, 0, 0, 1,   /* 0x50 .. 0x5F */
+    0, 1, 1, 1, 1, 1, 1, 1,    1, 1, 1, 1, 1, 1, 1, 1,   /* 0x60 .. 0x6F */
+    1, 1, 1, 1, 1, 1, 1, 1,    1, 1, 1, 0, 0, 0, 0, 0    /* 0x70 .. 0x7F */
+  };
+
+  return (t & 0x80) || aBareword[(int)t];
+}
+
+
+
+/*
+** 2014 Jun 09
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This is an SQLite module implementing full-text search.
+*/
+
+
+
+
+#define FTS5_DEFAULT_PAGE_SIZE   4050
+#define FTS5_DEFAULT_AUTOMERGE      4
+#define FTS5_DEFAULT_CRISISMERGE   16
+
+/* Maximum allowed page size */
+#define FTS5_MAX_PAGE_SIZE (128*1024)
+
+static int fts5_iswhitespace(char x){
+  return (x==' ');
+}
+
+static int fts5_isopenquote(char x){
+  return (x=='"' || x=='\'' || x=='[' || x=='`');
+}
+
+/*
+** Argument pIn points to a character that is part of a nul-terminated 
+** string. Return a pointer to the first character following *pIn in 
+** the string that is not a white-space character.
+*/
+static const char *fts5ConfigSkipWhitespace(const char *pIn){
+  const char *p = pIn;
+  if( p ){
+    while( fts5_iswhitespace(*p) ){ p++; }
+  }
+  return p;
+}
+
+/*
+** Argument pIn points to a character that is part of a nul-terminated 
+** string. Return a pointer to the first character following *pIn in 
+** the string that is not a "bareword" character.
+*/
+static const char *fts5ConfigSkipBareword(const char *pIn){
+  const char *p = pIn;
+  while ( sqlite3Fts5IsBareword(*p) ) p++;
+  if( p==pIn ) p = 0;
+  return p;
+}
+
+static int fts5_isdigit(char a){
+  return (a>='0' && a<='9');
+}
+
+
+
+static const char *fts5ConfigSkipLiteral(const char *pIn){
+  const char *p = pIn;
+  switch( *p ){
+    case 'n': case 'N':
+      if( sqlite3_strnicmp("null", p, 4)==0 ){
+        p = &p[4];
+      }else{
+        p = 0;
+      }
+      break;
+
+    case 'x': case 'X':
+      p++;
+      if( *p=='\'' ){
+        p++;
+        while( (*p>='a' && *p<='f') 
+            || (*p>='A' && *p<='F') 
+            || (*p>='0' && *p<='9') 
+            ){
+          p++;
+        }
+        if( *p=='\'' && 0==((p-pIn)%2) ){
+          p++;
+        }else{
+          p = 0;
+        }
+      }else{
+        p = 0;
+      }
+      break;
+
+    case '\'':
+      p++;
+      while( p ){
+        if( *p=='\'' ){
+          p++;
+          if( *p!='\'' ) break;
+        }
+        p++;
+        if( *p==0 ) p = 0;
+      }
+      break;
+
+    default:
+      /* maybe a number */
+      if( *p=='+' || *p=='-' ) p++;
+      while( fts5_isdigit(*p) ) p++;
+
+      /* At this point, if the literal was an integer, the parse is 
+      ** finished. Or, if it is a floating point value, it may continue
+      ** with either a decimal point or an 'E' character. */
+      if( *p=='.' && fts5_isdigit(p[1]) ){
+        p += 2;
+        while( fts5_isdigit(*p) ) p++;
+      }
+      if( p==pIn ) p = 0;
+
+      break;
+  }
+
+  return p;
+}
+
+/*
+** The first character of the string pointed to by argument z is guaranteed
+** to be an open-quote character (see function fts5_isopenquote()).
+**
+** This function searches for the corresponding close-quote character within
+** the string and, if found, dequotes the string in place and adds a new
+** nul-terminator byte.
+**
+** If the close-quote is found, the value returned is the byte offset of
+** the character immediately following it. Or, if the close-quote is not 
+** found, -1 is returned. If -1 is returned, the buffer is left in an 
+** undefined state.
+*/
+static int fts5Dequote(char *z){
+  char q;
+  int iIn = 1;
+  int iOut = 0;
+  q = z[0];
+
+  /* Set stack variable q to the close-quote character */
+  assert( q=='[' || q=='\'' || q=='"' || q=='`' );
+  if( q=='[' ) q = ']';  
+
+  while( ALWAYS(z[iIn]) ){
+    if( z[iIn]==q ){
+      if( z[iIn+1]!=q ){
+        /* Character iIn was the close quote. */
+        iIn++;
+        break;
+      }else{
+        /* Character iIn and iIn+1 form an escaped quote character. Skip
+        ** the input cursor past both and copy a single quote character 
+        ** to the output buffer. */
+        iIn += 2;
+        z[iOut++] = q;
+      }
+    }else{
+      z[iOut++] = z[iIn++];
+    }
+  }
+
+  z[iOut] = '\0';
+  return iIn;
+}
+
+/*
+** Convert an SQL-style quoted string into a normal string by removing
+** the quote characters.  The conversion is done in-place.  If the
+** input does not begin with a quote character, then this routine
+** is a no-op.
+**
+** Examples:
+**
+**     "abc"   becomes   abc
+**     'xyz'   becomes   xyz
+**     [pqr]   becomes   pqr
+**     `mno`   becomes   mno
+*/
+static void sqlite3Fts5Dequote(char *z){
+  char quote;                     /* Quote character (if any ) */
+
+  assert( 0==fts5_iswhitespace(z[0]) );
+  quote = z[0];
+  if( quote=='[' || quote=='\'' || quote=='"' || quote=='`' ){
+    fts5Dequote(z);
+  }
+}
+
+/*
+** Parse a "special" CREATE VIRTUAL TABLE directive and update
+** configuration object pConfig as appropriate.
+**
+** If successful, object pConfig is updated and SQLITE_OK returned. If
+** an error occurs, an SQLite error code is returned and an error message
+** may be left in *pzErr. It is the responsibility of the caller to
+** eventually free any such error message using sqlite3_free().
+*/
+static int fts5ConfigParseSpecial(
+  Fts5Global *pGlobal,
+  Fts5Config *pConfig,            /* Configuration object to update */
+  const char *zCmd,               /* Special command to parse */
+  const char *zArg,               /* Argument to parse */
+  char **pzErr                    /* OUT: Error message */
+){
+  int rc = SQLITE_OK;
+  int nCmd = strlen(zCmd);
+  if( sqlite3_strnicmp("prefix", zCmd, nCmd)==0 ){
+    const int nByte = sizeof(int) * FTS5_MAX_PREFIX_INDEXES;
+    const char *p;
+    if( pConfig->aPrefix ){
+      *pzErr = sqlite3_mprintf("multiple prefix=... directives");
+      rc = SQLITE_ERROR;
+    }else{
+      pConfig->aPrefix = sqlite3Fts5MallocZero(&rc, nByte);
+    }
+    p = zArg;
+    while( rc==SQLITE_OK && p[0] ){
+      int nPre = 0;
+      while( p[0]==' ' ) p++;
+      while( p[0]>='0' && p[0]<='9' && nPre<1000 ){
+        nPre = nPre*10 + (p[0] - '0');
+        p++;
+      }
+      while( p[0]==' ' ) p++;
+      if( p[0]==',' ){
+        p++;
+      }else if( p[0] ){
+        *pzErr = sqlite3_mprintf("malformed prefix=... directive");
+        rc = SQLITE_ERROR;
+      }
+      if( rc==SQLITE_OK && (nPre==0 || nPre>=1000) ){
+        *pzErr = sqlite3_mprintf("prefix length out of range: %d", nPre);
+        rc = SQLITE_ERROR;
+      }
+      pConfig->aPrefix[pConfig->nPrefix] = nPre;
+      pConfig->nPrefix++;
+    }
+    return rc;
+  }
+
+  if( sqlite3_strnicmp("tokenize", zCmd, nCmd)==0 ){
+    const char *p = (const char*)zArg;
+    int nArg = strlen(zArg) + 1;
+    char **azArg = sqlite3Fts5MallocZero(&rc, sizeof(char*) * nArg);
+    char *pDel = sqlite3Fts5MallocZero(&rc, nArg * 2);
+    char *pSpace = pDel;
+
+    if( azArg && pSpace ){
+      if( pConfig->pTok ){
+        *pzErr = sqlite3_mprintf("multiple tokenize=... directives");
+        rc = SQLITE_ERROR;
+      }else{
+        for(nArg=0; p && *p; nArg++){
+          const char *p2 = fts5ConfigSkipWhitespace(p);
+          if( *p2=='\'' ){
+            p = fts5ConfigSkipLiteral(p2);
+          }else{
+            p = fts5ConfigSkipBareword(p2);
+          }
+          if( p ){
+            memcpy(pSpace, p2, p-p2);
+            azArg[nArg] = pSpace;
+            sqlite3Fts5Dequote(pSpace);
+            pSpace += (p - p2) + 1;
+            p = fts5ConfigSkipWhitespace(p);
+          }
+        }
+        if( p==0 ){
+          *pzErr = sqlite3_mprintf("parse error in tokenize directive");
+          rc = SQLITE_ERROR;
+        }else{
+          rc = sqlite3Fts5GetTokenizer(pGlobal, 
+              (const char**)azArg, nArg, &pConfig->pTok, &pConfig->pTokApi,
+              pzErr
+          );
+        }
+      }
+    }
+
+    sqlite3_free(azArg);
+    sqlite3_free(pDel);
+    return rc;
+  }
+
+  if( sqlite3_strnicmp("content", zCmd, nCmd)==0 ){
+    if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){
+      *pzErr = sqlite3_mprintf("multiple content=... directives");
+      rc = SQLITE_ERROR;
+    }else{
+      if( zArg[0] ){
+        pConfig->eContent = FTS5_CONTENT_EXTERNAL;
+        pConfig->zContent = sqlite3Fts5Mprintf(&rc, "%Q.%Q", pConfig->zDb,zArg);
+      }else{
+        pConfig->eContent = FTS5_CONTENT_NONE;
+      }
+    }
+    return rc;
+  }
+
+  if( sqlite3_strnicmp("content_rowid", zCmd, nCmd)==0 ){
+    if( pConfig->zContentRowid ){
+      *pzErr = sqlite3_mprintf("multiple content_rowid=... directives");
+      rc = SQLITE_ERROR;
+    }else{
+      pConfig->zContentRowid = sqlite3Fts5Strndup(&rc, zArg, -1);
+    }
+    return rc;
+  }
+
+  if( sqlite3_strnicmp("columnsize", zCmd, nCmd)==0 ){
+    if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
+      *pzErr = sqlite3_mprintf("malformed columnsize=... directive");
+      rc = SQLITE_ERROR;
+    }else{
+      pConfig->bColumnsize = (zArg[0]=='1');
+    }
+    return rc;
+  }
+
+  *pzErr = sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd);
+  return SQLITE_ERROR;
+}
+
+/*
+** Allocate an instance of the default tokenizer ("simple") at 
+** Fts5Config.pTokenizer. Return SQLITE_OK if successful, or an SQLite error
+** code if an error occurs.
+*/
+static int fts5ConfigDefaultTokenizer(Fts5Global *pGlobal, Fts5Config *pConfig){
+  assert( pConfig->pTok==0 && pConfig->pTokApi==0 );
+  return sqlite3Fts5GetTokenizer(
+      pGlobal, 0, 0, &pConfig->pTok, &pConfig->pTokApi, 0
+  );
+}
+
+/*
+** Gobble up the first bareword or quoted word from the input buffer zIn.
+** Return a pointer to the character immediately following the last in
+** the gobbled word if successful, or a NULL pointer otherwise (failed
+** to find close-quote character).
+**
+** Before returning, set pzOut to point to a new buffer containing a
+** nul-terminated, dequoted copy of the gobbled word. If the word was
+** quoted, *pbQuoted is also set to 1 before returning.
+**
+** If *pRc is other than SQLITE_OK when this function is called, it is
+** a no-op (NULL is returned). Otherwise, if an OOM occurs within this
+** function, *pRc is set to SQLITE_NOMEM before returning. *pRc is *not*
+** set if a parse error (failed to find close quote) occurs.
+*/
+static const char *fts5ConfigGobbleWord(
+  int *pRc,                       /* IN/OUT: Error code */
+  const char *zIn,                /* Buffer to gobble string/bareword from */
+  char **pzOut,                   /* OUT: malloc'd buffer containing str/bw */
+  int *pbQuoted                   /* OUT: Set to true if dequoting required */
+){
+  const char *zRet = 0;
+
+  int nIn = strlen(zIn);
+  char *zOut = sqlite3_malloc(nIn+1);
+
+  assert( *pRc==SQLITE_OK );
+  *pbQuoted = 0;
+  *pzOut = 0;
+
+  if( zOut==0 ){
+    *pRc = SQLITE_NOMEM;
+  }else{
+    memcpy(zOut, zIn, nIn+1);
+    if( fts5_isopenquote(zOut[0]) ){
+      int ii = fts5Dequote(zOut);
+      zRet = &zIn[ii];
+      *pbQuoted = 1;
+    }else{
+      zRet = fts5ConfigSkipBareword(zIn);
+      zOut[zRet-zIn] = '\0';
+    }
+  }
+
+  if( zRet==0 ){
+    sqlite3_free(zOut);
+  }else{
+    *pzOut = zOut;
+  }
+
+  return zRet;
+}
+
+static int fts5ConfigParseColumn(
+  Fts5Config *p, 
+  char *zCol, 
+  char *zArg, 
+  char **pzErr
+){
+  int rc = SQLITE_OK;
+  if( 0==sqlite3_stricmp(zCol, FTS5_RANK_NAME) 
+   || 0==sqlite3_stricmp(zCol, FTS5_ROWID_NAME) 
+  ){
+    *pzErr = sqlite3_mprintf("reserved fts5 column name: %s", zCol);
+    rc = SQLITE_ERROR;
+  }else if( zArg ){
+    if( 0==sqlite3_stricmp(zArg, "unindexed") ){
+      p->abUnindexed[p->nCol] = 1;
+    }else{
+      *pzErr = sqlite3_mprintf("unrecognized column option: %s", zArg);
+      rc = SQLITE_ERROR;
+    }
+  }
+
+  p->azCol[p->nCol++] = zCol;
+  return rc;
+}
+
+/*
+** Populate the Fts5Config.zContentExprlist string.
+*/
+static int fts5ConfigMakeExprlist(Fts5Config *p){
+  int i;
+  int rc = SQLITE_OK;
+  Fts5Buffer buf = {0, 0, 0};
+
+  sqlite3Fts5BufferAppendPrintf(&rc, &buf, "T.%Q", p->zContentRowid);
+  if( p->eContent!=FTS5_CONTENT_NONE ){
+    for(i=0; i<p->nCol; i++){
+      if( p->eContent==FTS5_CONTENT_EXTERNAL ){
+        sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.%Q", p->azCol[i]);
+      }else{
+        sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.c%d", i);
+      }
+    }
+  }
+
+  assert( p->zContentExprlist==0 );
+  p->zContentExprlist = (char*)buf.p;
+  return rc;
+}
+
+/*
+** Arguments nArg/azArg contain the string arguments passed to the xCreate
+** or xConnect method of the virtual table. This function attempts to 
+** allocate an instance of Fts5Config containing the results of parsing
+** those arguments.
+**
+** If successful, SQLITE_OK is returned and *ppOut is set to point to the
+** new Fts5Config object. If an error occurs, an SQLite error code is 
+** returned, *ppOut is set to NULL and an error message may be left in
+** *pzErr. It is the responsibility of the caller to eventually free any 
+** such error message using sqlite3_free().
+*/
+static int sqlite3Fts5ConfigParse(
+  Fts5Global *pGlobal,
+  sqlite3 *db,
+  int nArg,                       /* Number of arguments */
+  const char **azArg,             /* Array of nArg CREATE VIRTUAL TABLE args */
+  Fts5Config **ppOut,             /* OUT: Results of parse */
+  char **pzErr                    /* OUT: Error message */
+){
+  int rc = SQLITE_OK;             /* Return code */
+  Fts5Config *pRet;               /* New object to return */
+  int i;
+  int nByte;
+
+  *ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config));
+  if( pRet==0 ) return SQLITE_NOMEM;
+  memset(pRet, 0, sizeof(Fts5Config));
+  pRet->db = db;
+  pRet->iCookie = -1;
+
+  nByte = nArg * (sizeof(char*) + sizeof(u8));
+  pRet->azCol = (char**)sqlite3Fts5MallocZero(&rc, nByte);
+  pRet->abUnindexed = (u8*)&pRet->azCol[nArg];
+  pRet->zDb = sqlite3Fts5Strndup(&rc, azArg[1], -1);
+  pRet->zName = sqlite3Fts5Strndup(&rc, azArg[2], -1);
+  pRet->bColumnsize = 1;
+#ifdef SQLITE_DEBUG
+  pRet->bPrefixIndex = 1;
+#endif
+  if( rc==SQLITE_OK && sqlite3_stricmp(pRet->zName, FTS5_RANK_NAME)==0 ){
+    *pzErr = sqlite3_mprintf("reserved fts5 table name: %s", pRet->zName);
+    rc = SQLITE_ERROR;
+  }
+
+  for(i=3; rc==SQLITE_OK && i<nArg; i++){
+    const char *zOrig = azArg[i];
+    const char *z;
+    char *zOne = 0;
+    char *zTwo = 0;
+    int bOption = 0;
+    int bMustBeCol = 0;
+
+    z = fts5ConfigGobbleWord(&rc, zOrig, &zOne, &bMustBeCol);
+    z = fts5ConfigSkipWhitespace(z);
+    if( z && *z=='=' ){
+      bOption = 1;
+      z++;
+      if( bMustBeCol ) z = 0;
+    }
+    z = fts5ConfigSkipWhitespace(z);
+    if( z && z[0] ){
+      int bDummy;
+      z = fts5ConfigGobbleWord(&rc, z, &zTwo, &bDummy);
+      if( z && z[0] ) z = 0;
+    }
+
+    if( rc==SQLITE_OK ){
+      if( z==0 ){
+        *pzErr = sqlite3_mprintf("parse error in \"%s\"", zOrig);
+        rc = SQLITE_ERROR;
+      }else{
+        if( bOption ){
+          rc = fts5ConfigParseSpecial(pGlobal, pRet, zOne, zTwo?zTwo:"", pzErr);
+        }else{
+          rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr);
+          zOne = 0;
+        }
+      }
+    }
+
+    sqlite3_free(zOne);
+    sqlite3_free(zTwo);
+  }
+
+  /* If a tokenizer= option was successfully parsed, the tokenizer has
+  ** already been allocated. Otherwise, allocate an instance of the default
+  ** tokenizer (unicode61) now.  */
+  if( rc==SQLITE_OK && pRet->pTok==0 ){
+    rc = fts5ConfigDefaultTokenizer(pGlobal, pRet);
+  }
+
+  /* If no zContent option was specified, fill in the default values. */
+  if( rc==SQLITE_OK && pRet->zContent==0 ){
+    const char *zTail = 0;
+    assert( pRet->eContent==FTS5_CONTENT_NORMAL 
+         || pRet->eContent==FTS5_CONTENT_NONE 
+    );
+    if( pRet->eContent==FTS5_CONTENT_NORMAL ){
+      zTail = "content";
+    }else if( pRet->bColumnsize ){
+      zTail = "docsize";
+    }
+
+    if( zTail ){
+      pRet->zContent = sqlite3Fts5Mprintf(
+          &rc, "%Q.'%q_%s'", pRet->zDb, pRet->zName, zTail
+      );
+    }
+  }
+
+  if( rc==SQLITE_OK && pRet->zContentRowid==0 ){
+    pRet->zContentRowid = sqlite3Fts5Strndup(&rc, "rowid", -1);
+  }
+
+  /* Formulate the zContentExprlist text */
+  if( rc==SQLITE_OK ){
+    rc = fts5ConfigMakeExprlist(pRet);
+  }
+
+  if( rc!=SQLITE_OK ){
+    sqlite3Fts5ConfigFree(pRet);
+    *ppOut = 0;
+  }
+  return rc;
+}
+
+/*
+** Free the configuration object passed as the only argument.
+*/
+static void sqlite3Fts5ConfigFree(Fts5Config *pConfig){
+  if( pConfig ){
+    int i;
+    if( pConfig->pTok ){
+      pConfig->pTokApi->xDelete(pConfig->pTok);
+    }
+    sqlite3_free(pConfig->zDb);
+    sqlite3_free(pConfig->zName);
+    for(i=0; i<pConfig->nCol; i++){
+      sqlite3_free(pConfig->azCol[i]);
+    }
+    sqlite3_free(pConfig->azCol);
+    sqlite3_free(pConfig->aPrefix);
+    sqlite3_free(pConfig->zRank);
+    sqlite3_free(pConfig->zRankArgs);
+    sqlite3_free(pConfig->zContent);
+    sqlite3_free(pConfig->zContentRowid);
+    sqlite3_free(pConfig->zContentExprlist);
+    sqlite3_free(pConfig);
+  }
+}
+
+/*
+** Call sqlite3_declare_vtab() based on the contents of the configuration
+** object passed as the only argument. Return SQLITE_OK if successful, or
+** an SQLite error code if an error occurs.
+*/
+static int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig){
+  int i;
+  int rc = SQLITE_OK;
+  char *zSql;
+
+  zSql = sqlite3Fts5Mprintf(&rc, "CREATE TABLE x(");
+  for(i=0; zSql && i<pConfig->nCol; i++){
+    const char *zSep = (i==0?"":", ");
+    zSql = sqlite3Fts5Mprintf(&rc, "%z%s%Q", zSql, zSep, pConfig->azCol[i]);
+  }
+  zSql = sqlite3Fts5Mprintf(&rc, "%z, %Q HIDDEN, %s HIDDEN)", 
+      zSql, pConfig->zName, FTS5_RANK_NAME
+  );
+
+  assert( zSql || rc==SQLITE_NOMEM );
+  if( zSql ){
+    rc = sqlite3_declare_vtab(pConfig->db, zSql);
+    sqlite3_free(zSql);
+  }
+  
+  return rc;
+}
+
+/*
+** Tokenize the text passed via the second and third arguments.
+**
+** The callback is invoked once for each token in the input text. The
+** arguments passed to it are, in order:
+**
+**     void *pCtx          // Copy of 4th argument to sqlite3Fts5Tokenize()
+**     const char *pToken  // Pointer to buffer containing token
+**     int nToken          // Size of token in bytes
+**     int iStart          // Byte offset of start of token within input text
+**     int iEnd            // Byte offset of end of token within input text
+**     int iPos            // Position of token in input (first token is 0)
+**
+** If the callback returns a non-zero value the tokenization is abandoned
+** and no further callbacks are issued. 
+**
+** This function returns SQLITE_OK if successful or an SQLite error code
+** if an error occurs. If the tokenization was abandoned early because
+** the callback returned SQLITE_DONE, this is not an error and this function
+** still returns SQLITE_OK. Or, if the tokenization was abandoned early
+** because the callback returned another non-zero value, it is assumed
+** to be an SQLite error code and returned to the caller.
+*/
+static int sqlite3Fts5Tokenize(
+  Fts5Config *pConfig,            /* FTS5 Configuration object */
+  int flags,                      /* FTS5_TOKENIZE_* flags */
+  const char *pText, int nText,   /* Text to tokenize */
+  void *pCtx,                     /* Context passed to xToken() */
+  int (*xToken)(void*, int, const char*, int, int, int)    /* Callback */
+){
+  if( pText==0 ) return SQLITE_OK;
+  return pConfig->pTokApi->xTokenize(
+      pConfig->pTok, pCtx, flags, pText, nText, xToken
+  );
+}
+
+/*
+** Argument pIn points to the first character in what is expected to be
+** a comma-separated list of SQL literals followed by a ')' character.
+** If it actually is this, return a pointer to the ')'. Otherwise, return
+** NULL to indicate a parse error.
+*/
+static const char *fts5ConfigSkipArgs(const char *pIn){
+  const char *p = pIn;
+  
+  while( 1 ){
+    p = fts5ConfigSkipWhitespace(p);
+    p = fts5ConfigSkipLiteral(p);
+    p = fts5ConfigSkipWhitespace(p);
+    if( p==0 || *p==')' ) break;
+    if( *p!=',' ){
+      p = 0;
+      break;
+    }
+    p++;
+  }
+
+  return p;
+}
+
+/*
+** Parameter zIn contains a rank() function specification. The format of 
+** this is:
+**
+**   + Bareword (function name)
+**   + Open parenthesis - "("
+**   + Zero or more SQL literals in a comma separated list
+**   + Close parenthesis - ")"
+*/
+static int sqlite3Fts5ConfigParseRank(
+  const char *zIn,                /* Input string */
+  char **pzRank,                  /* OUT: Rank function name */
+  char **pzRankArgs               /* OUT: Rank function arguments */
+){
+  const char *p = zIn;
+  const char *pRank;
+  char *zRank = 0;
+  char *zRankArgs = 0;
+  int rc = SQLITE_OK;
+
+  *pzRank = 0;
+  *pzRankArgs = 0;
+
+  p = fts5ConfigSkipWhitespace(p);
+  pRank = p;
+  p = fts5ConfigSkipBareword(p);
+
+  if( p ){
+    zRank = sqlite3Fts5MallocZero(&rc, 1 + p - pRank);
+    if( zRank ) memcpy(zRank, pRank, p-pRank);
+  }else{
+    rc = SQLITE_ERROR;
+  }
+
+  if( rc==SQLITE_OK ){
+    p = fts5ConfigSkipWhitespace(p);
+    if( *p!='(' ) rc = SQLITE_ERROR;
+    p++;
+  }
+  if( rc==SQLITE_OK ){
+    const char *pArgs; 
+    p = fts5ConfigSkipWhitespace(p);
+    pArgs = p;
+    if( *p!=')' ){
+      p = fts5ConfigSkipArgs(p);
+      if( p==0 ){
+        rc = SQLITE_ERROR;
+      }else{
+        zRankArgs = sqlite3Fts5MallocZero(&rc, 1 + p - pArgs);
+        if( zRankArgs ) memcpy(zRankArgs, pArgs, p-pArgs);
+      }
+    }
+  }
+
+  if( rc!=SQLITE_OK ){
+    sqlite3_free(zRank);
+    assert( zRankArgs==0 );
+  }else{
+    *pzRank = zRank;
+    *pzRankArgs = zRankArgs;
+  }
+  return rc;
+}
+
+static int sqlite3Fts5ConfigSetValue(
+  Fts5Config *pConfig, 
+  const char *zKey, 
+  sqlite3_value *pVal,
+  int *pbBadkey
+){
+  int rc = SQLITE_OK;
+
+  if( 0==sqlite3_stricmp(zKey, "pgsz") ){
+    int pgsz = 0;
+    if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
+      pgsz = sqlite3_value_int(pVal);
+    }
+    if( pgsz<=0 || pgsz>FTS5_MAX_PAGE_SIZE ){
+      *pbBadkey = 1;
+    }else{
+      pConfig->pgsz = pgsz;
+    }
+  }
+
+  else if( 0==sqlite3_stricmp(zKey, "automerge") ){
+    int nAutomerge = -1;
+    if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
+      nAutomerge = sqlite3_value_int(pVal);
+    }
+    if( nAutomerge<0 || nAutomerge>64 ){
+      *pbBadkey = 1;
+    }else{
+      if( nAutomerge==1 ) nAutomerge = FTS5_DEFAULT_AUTOMERGE;
+      pConfig->nAutomerge = nAutomerge;
+    }
+  }
+
+  else if( 0==sqlite3_stricmp(zKey, "crisismerge") ){
+    int nCrisisMerge = -1;
+    if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
+      nCrisisMerge = sqlite3_value_int(pVal);
+    }
+    if( nCrisisMerge<0 ){
+      *pbBadkey = 1;
+    }else{
+      if( nCrisisMerge<=1 ) nCrisisMerge = FTS5_DEFAULT_CRISISMERGE;
+      pConfig->nCrisisMerge = nCrisisMerge;
+    }
+  }
+
+  else if( 0==sqlite3_stricmp(zKey, "rank") ){
+    const char *zIn = (const char*)sqlite3_value_text(pVal);
+    char *zRank;
+    char *zRankArgs;
+    rc = sqlite3Fts5ConfigParseRank(zIn, &zRank, &zRankArgs);
+    if( rc==SQLITE_OK ){
+      sqlite3_free(pConfig->zRank);
+      sqlite3_free(pConfig->zRankArgs);
+      pConfig->zRank = zRank;
+      pConfig->zRankArgs = zRankArgs;
+    }else if( rc==SQLITE_ERROR ){
+      rc = SQLITE_OK;
+      *pbBadkey = 1;
+    }
+  }else{
+    *pbBadkey = 1;
+  }
+  return rc;
+}
+
+/*
+** Load the contents of the %_config table into memory.
+*/
+static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
+  const char *zSelect = "SELECT k, v FROM %Q.'%q_config'";
+  char *zSql;
+  sqlite3_stmt *p = 0;
+  int rc = SQLITE_OK;
+  int iVersion = 0;
+
+  /* Set default values */
+  pConfig->pgsz = FTS5_DEFAULT_PAGE_SIZE;
+  pConfig->nAutomerge = FTS5_DEFAULT_AUTOMERGE;
+  pConfig->nCrisisMerge = FTS5_DEFAULT_CRISISMERGE;
+
+  zSql = sqlite3Fts5Mprintf(&rc, zSelect, pConfig->zDb, pConfig->zName);
+  if( zSql ){
+    rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &p, 0);
+    sqlite3_free(zSql);
+  }
+
+  assert( rc==SQLITE_OK || p==0 );
+  if( rc==SQLITE_OK ){
+    while( SQLITE_ROW==sqlite3_step(p) ){
+      const char *zK = (const char*)sqlite3_column_text(p, 0);
+      sqlite3_value *pVal = sqlite3_column_value(p, 1);
+      if( 0==sqlite3_stricmp(zK, "version") ){
+        iVersion = sqlite3_value_int(pVal);
+      }else{
+        int bDummy = 0;
+        sqlite3Fts5ConfigSetValue(pConfig, zK, pVal, &bDummy);
+      }
+    }
+    rc = sqlite3_finalize(p);
+  }
+  
+  if( rc==SQLITE_OK && iVersion!=FTS5_CURRENT_VERSION ){
+    rc = SQLITE_ERROR;
+    if( pConfig->pzErrmsg ){
+      assert( 0==*pConfig->pzErrmsg );
+      *pConfig->pzErrmsg = sqlite3_mprintf(
+          "invalid fts5 file format (found %d, expected %d) - run 'rebuild'",
+          iVersion, FTS5_CURRENT_VERSION
+      );
+    }
+  }
+
+  if( rc==SQLITE_OK ){
+    pConfig->iCookie = iCookie;
+  }
+  return rc;
+}
+
+
+/*
+** 2014 May 31
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+*/
+
+
+
+
+/*
+** All token types in the generated fts5parse.h file are greater than 0.
+*/
+#define FTS5_EOF 0
+
+#define FTS5_LARGEST_INT64  (0xffffffff|(((i64)0x7fffffff)<<32))
+
+typedef struct Fts5ExprTerm Fts5ExprTerm;
+
+/*
+** Functions generated by lemon from fts5parse.y.
+*/
+static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(u64));
+static void sqlite3Fts5ParserFree(void*, void (*freeProc)(void*));
+static void sqlite3Fts5Parser(void*, int, Fts5Token, Fts5Parse*);
+#ifndef NDEBUG
+/* #include <stdio.h> */
+static void sqlite3Fts5ParserTrace(FILE*, char*);
+#endif
+
+
+struct Fts5Expr {
+  Fts5Index *pIndex;
+  Fts5ExprNode *pRoot;
+  int bDesc;                      /* Iterate in descending rowid order */
+  int nPhrase;                    /* Number of phrases in expression */
+  Fts5ExprPhrase **apExprPhrase;  /* Pointers to phrase objects */
+};
+
+/*
+** eType:
+**   Expression node type. Always one of:
+**
+**       FTS5_AND                 (nChild, apChild valid)
+**       FTS5_OR                  (nChild, apChild valid)
+**       FTS5_NOT                 (nChild, apChild valid)
+**       FTS5_STRING              (pNear valid)
+**       FTS5_TERM                (pNear valid)
+*/
+struct Fts5ExprNode {
+  int eType;                      /* Node type */
+  int bEof;                       /* True at EOF */
+  int bNomatch;                   /* True if entry is not a match */
+
+  i64 iRowid;                     /* Current rowid */
+  Fts5ExprNearset *pNear;         /* For FTS5_STRING - cluster of phrases */
+
+  /* Child nodes. For a NOT node, this array always contains 2 entries. For 
+  ** AND or OR nodes, it contains 2 or more entries.  */
+  int nChild;                     /* Number of child nodes */
+  Fts5ExprNode *apChild[1];       /* Array of child nodes */
+};
+
+#define Fts5NodeIsString(p) ((p)->eType==FTS5_TERM || (p)->eType==FTS5_STRING)
+
+/*
+** An instance of the following structure represents a single search term
+** or term prefix.
+*/
+struct Fts5ExprTerm {
+  int bPrefix;                    /* True for a prefix term */
+  char *zTerm;                    /* nul-terminated term */
+  Fts5IndexIter *pIter;           /* Iterator for this term */
+  Fts5ExprTerm *pSynonym;         /* Pointer to first in list of synonyms */
+};
+
+/*
+** A phrase. One or more terms that must appear in a contiguous sequence
+** within a document for it to match.
+*/
+struct Fts5ExprPhrase {
+  Fts5ExprNode *pNode;            /* FTS5_STRING node this phrase is part of */
+  Fts5Buffer poslist;             /* Current position list */
+  int nTerm;                      /* Number of entries in aTerm[] */
+  Fts5ExprTerm aTerm[1];          /* Terms that make up this phrase */
+};
+
+/*
+** One or more phrases that must appear within a certain token distance of
+** each other within each matching document.
+*/
+struct Fts5ExprNearset {
+  int nNear;                      /* NEAR parameter */
+  Fts5Colset *pColset;            /* Columns to search (NULL -> all columns) */
+  int nPhrase;                    /* Number of entries in aPhrase[] array */
+  Fts5ExprPhrase *apPhrase[1];    /* Array of phrase pointers */
+};
+
+
+/*
+** Parse context.
+*/
+struct Fts5Parse {
+  Fts5Config *pConfig;
+  char *zErr;
+  int rc;
+  int nPhrase;                    /* Size of apPhrase array */
+  Fts5ExprPhrase **apPhrase;      /* Array of all phrases */
+  Fts5ExprNode *pExpr;            /* Result of a successful parse */
+};
+
+static void sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...){
+  va_list ap;
+  va_start(ap, zFmt);
+  if( pParse->rc==SQLITE_OK ){
+    pParse->zErr = sqlite3_vmprintf(zFmt, ap);
+    pParse->rc = SQLITE_ERROR;
+  }
+  va_end(ap);
+}
+
+static int fts5ExprIsspace(char t){
+  return t==' ' || t=='\t' || t=='\n' || t=='\r';
+}
+
+/*
+** Read the first token from the nul-terminated string at *pz.
+*/
+static int fts5ExprGetToken(
+  Fts5Parse *pParse, 
+  const char **pz,                /* IN/OUT: Pointer into buffer */
+  Fts5Token *pToken
+){
+  const char *z = *pz;
+  int tok;
+
+  /* Skip past any whitespace */
+  while( fts5ExprIsspace(*z) ) z++;
+
+  pToken->p = z;
+  pToken->n = 1;
+  switch( *z ){
+    case '(':  tok = FTS5_LP;    break;
+    case ')':  tok = FTS5_RP;    break;
+    case '{':  tok = FTS5_LCP;   break;
+    case '}':  tok = FTS5_RCP;   break;
+    case ':':  tok = FTS5_COLON; break;
+    case ',':  tok = FTS5_COMMA; break;
+    case '+':  tok = FTS5_PLUS;  break;
+    case '*':  tok = FTS5_STAR;  break;
+    case '\0': tok = FTS5_EOF;   break;
+
+    case '"': {
+      const char *z2;
+      tok = FTS5_STRING;
+
+      for(z2=&z[1]; 1; z2++){
+        if( z2[0]=='"' ){
+          z2++;
+          if( z2[0]!='"' ) break;
+        }
+        if( z2[0]=='\0' ){
+          sqlite3Fts5ParseError(pParse, "unterminated string");
+          return FTS5_EOF;
+        }
+      }
+      pToken->n = (z2 - z);
+      break;
+    }
+
+    default: {
+      const char *z2;
+      if( sqlite3Fts5IsBareword(z[0])==0 ){
+        sqlite3Fts5ParseError(pParse, "fts5: syntax error near \"%.1s\"", z);
+        return FTS5_EOF;
+      }
+      tok = FTS5_STRING;
+      for(z2=&z[1]; sqlite3Fts5IsBareword(*z2); z2++);
+      pToken->n = (z2 - z);
+      if( pToken->n==2 && memcmp(pToken->p, "OR", 2)==0 )  tok = FTS5_OR;
+      if( pToken->n==3 && memcmp(pToken->p, "NOT", 3)==0 ) tok = FTS5_NOT;
+      if( pToken->n==3 && memcmp(pToken->p, "AND", 3)==0 ) tok = FTS5_AND;
+      break;
+    }
+  }
+
+  *pz = &pToken->p[pToken->n];
+  return tok;
+}
+
+static void *fts5ParseAlloc(u64 t){ return sqlite3_malloc((int)t); }
+static void fts5ParseFree(void *p){ sqlite3_free(p); }
+
+static int sqlite3Fts5ExprNew(
+  Fts5Config *pConfig,            /* FTS5 Configuration */
+  const char *zExpr,              /* Expression text */
+  Fts5Expr **ppNew, 
+  char **pzErr
+){
+  Fts5Parse sParse;
+  Fts5Token token;
+  const char *z = zExpr;
+  int t;                          /* Next token type */
+  void *pEngine;
+  Fts5Expr *pNew;
+
+  *ppNew = 0;
+  *pzErr = 0;
+  memset(&sParse, 0, sizeof(sParse));
+  pEngine = sqlite3Fts5ParserAlloc(fts5ParseAlloc);
+  if( pEngine==0 ){ return SQLITE_NOMEM; }
+  sParse.pConfig = pConfig;
+
+  do {
+    t = fts5ExprGetToken(&sParse, &z, &token);
+    sqlite3Fts5Parser(pEngine, t, token, &sParse);
+  }while( sParse.rc==SQLITE_OK && t!=FTS5_EOF );
+  sqlite3Fts5ParserFree(pEngine, fts5ParseFree);
+
+  assert( sParse.rc!=SQLITE_OK || sParse.zErr==0 );
+  if( sParse.rc==SQLITE_OK ){
+    *ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr));
+    if( pNew==0 ){
+      sParse.rc = SQLITE_NOMEM;
+      sqlite3Fts5ParseNodeFree(sParse.pExpr);
+    }else{
+      pNew->pRoot = sParse.pExpr;
+      pNew->pIndex = 0;
+      pNew->apExprPhrase = sParse.apPhrase;
+      pNew->nPhrase = sParse.nPhrase;
+      sParse.apPhrase = 0;
+    }
+  }
+
+  sqlite3_free(sParse.apPhrase);
+  *pzErr = sParse.zErr;
+  return sParse.rc;
+}
+
+/*
+** Free the expression node object passed as the only argument.
+*/
+static void sqlite3Fts5ParseNodeFree(Fts5ExprNode *p){
+  if( p ){
+    int i;
+    for(i=0; i<p->nChild; i++){
+      sqlite3Fts5ParseNodeFree(p->apChild[i]);
+    }
+    sqlite3Fts5ParseNearsetFree(p->pNear);
+    sqlite3_free(p);
+  }
+}
+
+/*
+** Free the expression object passed as the only argument.
+*/
+static void sqlite3Fts5ExprFree(Fts5Expr *p){
+  if( p ){
+    sqlite3Fts5ParseNodeFree(p->pRoot);
+    sqlite3_free(p->apExprPhrase);
+    sqlite3_free(p);
+  }
+}
+
+/*
+** Argument pTerm must be a synonym iterator. Return the current rowid
+** that it points to.
+*/
+static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){
+  i64 iRet = 0;
+  int bRetValid = 0;
+  Fts5ExprTerm *p;
+
+  assert( pTerm->pSynonym );
+  assert( bDesc==0 || bDesc==1 );
+  for(p=pTerm; p; p=p->pSynonym){
+    if( 0==sqlite3Fts5IterEof(p->pIter) ){
+      i64 iRowid = sqlite3Fts5IterRowid(p->pIter);
+      if( bRetValid==0 || (bDesc!=(iRowid<iRet)) ){
+        iRet = iRowid;
+        bRetValid = 1;
+      }
+    }
+  }
+
+  if( pbEof && bRetValid==0 ) *pbEof = 1;
+  return iRet;
+}
+
+/*
+** Argument pTerm must be a synonym iterator.
+*/
+static int fts5ExprSynonymPoslist(
+  Fts5ExprTerm *pTerm, 
+  Fts5Colset *pColset,
+  i64 iRowid,
+  int *pbDel,                     /* OUT: Caller should sqlite3_free(*pa) */
+  u8 **pa, int *pn
+){
+  Fts5PoslistReader aStatic[4];
+  Fts5PoslistReader *aIter = aStatic;
+  int nIter = 0;
+  int nAlloc = 4;
+  int rc = SQLITE_OK;
+  Fts5ExprTerm *p;
+
+  assert( pTerm->pSynonym );
+  for(p=pTerm; p; p=p->pSynonym){
+    Fts5IndexIter *pIter = p->pIter;
+    if( sqlite3Fts5IterEof(pIter)==0 && sqlite3Fts5IterRowid(pIter)==iRowid ){
+      const u8 *a;
+      int n;
+      i64 dummy;
+      rc = sqlite3Fts5IterPoslist(pIter, pColset, &a, &n, &dummy);
+      if( rc!=SQLITE_OK ) goto synonym_poslist_out;
+      if( nIter==nAlloc ){
+        int nByte = sizeof(Fts5PoslistReader) * nAlloc * 2;
+        Fts5PoslistReader *aNew = (Fts5PoslistReader*)sqlite3_malloc(nByte);
+        if( aNew==0 ){
+          rc = SQLITE_NOMEM;
+          goto synonym_poslist_out;
+        }
+        memcpy(aNew, aIter, sizeof(Fts5PoslistReader) * nIter);
+        nAlloc = nAlloc*2;
+        if( aIter!=aStatic ) sqlite3_free(aIter);
+        aIter = aNew;
+      }
+      sqlite3Fts5PoslistReaderInit(a, n, &aIter[nIter]);
+      assert( aIter[nIter].bEof==0 );
+      nIter++;
+    }
+  }
+
+  assert( *pbDel==0 );
+  if( nIter==1 ){
+    *pa = (u8*)aIter[0].a;
+    *pn = aIter[0].n;
+  }else{
+    Fts5PoslistWriter writer = {0};
+    Fts5Buffer buf = {0,0,0};
+    i64 iPrev = -1;
+    while( 1 ){
+      int i;
+      i64 iMin = FTS5_LARGEST_INT64;
+      for(i=0; i<nIter; i++){
+        if( aIter[i].bEof==0 ){
+          if( aIter[i].iPos==iPrev ){
+            if( sqlite3Fts5PoslistReaderNext(&aIter[i]) ) continue;
+          }
+          if( aIter[i].iPos<iMin ){
+            iMin = aIter[i].iPos;
+          }
+        }
+      }
+      if( iMin==FTS5_LARGEST_INT64 || rc!=SQLITE_OK ) break;
+      rc = sqlite3Fts5PoslistWriterAppend(&buf, &writer, iMin);
+      iPrev = iMin;
+    }
+    if( rc ){
+      sqlite3_free(buf.p);
+    }else{
+      *pa = buf.p;
+      *pn = buf.n;
+      *pbDel = 1;
+    }
+  }
+
+ synonym_poslist_out:
+  if( aIter!=aStatic ) sqlite3_free(aIter);
+  return rc;
+}
+
+
+/*
+** All individual term iterators in pPhrase are guaranteed to be valid and
+** pointing to the same rowid when this function is called. This function 
+** checks if the current rowid really is a match, and if so populates
+** the pPhrase->poslist buffer accordingly. Output parameter *pbMatch
+** is set to true if this is really a match, or false otherwise.
+**
+** SQLITE_OK is returned if an error occurs, or an SQLite error code 
+** otherwise. It is not considered an error code if the current rowid is 
+** not a match.
+*/
+static int fts5ExprPhraseIsMatch(
+  Fts5ExprNode *pNode,            /* Node pPhrase belongs to */
+  Fts5Colset *pColset,            /* Restrict matches to these columns */
+  Fts5ExprPhrase *pPhrase,        /* Phrase object to initialize */
+  int *pbMatch                    /* OUT: Set to true if really a match */
+){
+  Fts5PoslistWriter writer = {0};
+  Fts5PoslistReader aStatic[4];
+  Fts5PoslistReader *aIter = aStatic;
+  int i;
+  int rc = SQLITE_OK;
+  
+  fts5BufferZero(&pPhrase->poslist);
+
+  /* If the aStatic[] array is not large enough, allocate a large array
+  ** using sqlite3_malloc(). This approach could be improved upon. */
+  if( pPhrase->nTerm>(sizeof(aStatic) / sizeof(aStatic[0])) ){
+    int nByte = sizeof(Fts5PoslistReader) * pPhrase->nTerm;
+    aIter = (Fts5PoslistReader*)sqlite3_malloc(nByte);
+    if( !aIter ) return SQLITE_NOMEM;
+  }
+  memset(aIter, 0, sizeof(Fts5PoslistReader) * pPhrase->nTerm);
+
+  /* Initialize a term iterator for each term in the phrase */
+  for(i=0; i<pPhrase->nTerm; i++){
+    Fts5ExprTerm *pTerm = &pPhrase->aTerm[i];
+    i64 dummy;
+    int n = 0;
+    int bFlag = 0;
+    const u8 *a = 0;
+    if( pTerm->pSynonym ){
+      rc = fts5ExprSynonymPoslist(
+          pTerm, pColset, pNode->iRowid, &bFlag, (u8**)&a, &n
+      );
+    }else{
+      rc = sqlite3Fts5IterPoslist(pTerm->pIter, pColset, &a, &n, &dummy);
+    }
+    if( rc!=SQLITE_OK ) goto ismatch_out;
+    sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
+    aIter[i].bFlag = bFlag;
+    if( aIter[i].bEof ) goto ismatch_out;
+  }
+
+  while( 1 ){
+    int bMatch;
+    i64 iPos = aIter[0].iPos;
+    do {
+      bMatch = 1;
+      for(i=0; i<pPhrase->nTerm; i++){
+        Fts5PoslistReader *pPos = &aIter[i];
+        i64 iAdj = iPos + i;
+        if( pPos->iPos!=iAdj ){
+          bMatch = 0;
+          while( pPos->iPos<iAdj ){
+            if( sqlite3Fts5PoslistReaderNext(pPos) ) goto ismatch_out;
+          }
+          if( pPos->iPos>iAdj ) iPos = pPos->iPos-i;
+        }
+      }
+    }while( bMatch==0 );
+
+    /* Append position iPos to the output */
+    rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos);
+    if( rc!=SQLITE_OK ) goto ismatch_out;
+
+    for(i=0; i<pPhrase->nTerm; i++){
+      if( sqlite3Fts5PoslistReaderNext(&aIter[i]) ) goto ismatch_out;
+    }
+  }
+
+ ismatch_out:
+  *pbMatch = (pPhrase->poslist.n>0);
+  for(i=0; i<pPhrase->nTerm; i++){
+    if( aIter[i].bFlag ) sqlite3_free((u8*)aIter[i].a);
+  }
+  if( aIter!=aStatic ) sqlite3_free(aIter);
+  return rc;
+}
+
+typedef struct Fts5LookaheadReader Fts5LookaheadReader;
+struct Fts5LookaheadReader {
+  const u8 *a;                    /* Buffer containing position list */
+  int n;                          /* Size of buffer a[] in bytes */
+  int i;                          /* Current offset in position list */
+  i64 iPos;                       /* Current position */
+  i64 iLookahead;                 /* Next position */
+};
+
+#define FTS5_LOOKAHEAD_EOF (((i64)1) << 62)
+
+static int fts5LookaheadReaderNext(Fts5LookaheadReader *p){
+  p->iPos = p->iLookahead;
+  if( sqlite3Fts5PoslistNext64(p->a, p->n, &p->i, &p->iLookahead) ){
+    p->iLookahead = FTS5_LOOKAHEAD_EOF;
+  }
+  return (p->iPos==FTS5_LOOKAHEAD_EOF);
+}
+
+static int fts5LookaheadReaderInit(
+  const u8 *a, int n,             /* Buffer to read position list from */
+  Fts5LookaheadReader *p          /* Iterator object to initialize */
+){
+  memset(p, 0, sizeof(Fts5LookaheadReader));
+  p->a = a;
+  p->n = n;
+  fts5LookaheadReaderNext(p);
+  return fts5LookaheadReaderNext(p);
+}
+
+#if 0
+static int fts5LookaheadReaderEof(Fts5LookaheadReader *p){
+  return (p->iPos==FTS5_LOOKAHEAD_EOF);
+}
+#endif
+
+typedef struct Fts5NearTrimmer Fts5NearTrimmer;
+struct Fts5NearTrimmer {
+  Fts5LookaheadReader reader;     /* Input iterator */
+  Fts5PoslistWriter writer;       /* Writer context */
+  Fts5Buffer *pOut;               /* Output poslist */
+};
+
+/*
+** The near-set object passed as the first argument contains more than
+** one phrase. All phrases currently point to the same row. The
+** Fts5ExprPhrase.poslist buffers are populated accordingly. This function
+** tests if the current row contains instances of each phrase sufficiently
+** close together to meet the NEAR constraint. Non-zero is returned if it
+** does, or zero otherwise.
+**
+** If in/out parameter (*pRc) is set to other than SQLITE_OK when this
+** function is called, it is a no-op. Or, if an error (e.g. SQLITE_NOMEM)
+** occurs within this function (*pRc) is set accordingly before returning.
+** The return value is undefined in both these cases.
+** 
+** If no error occurs and non-zero (a match) is returned, the position-list
+** of each phrase object is edited to contain only those entries that
+** meet the constraint before returning.
+*/
+static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){
+  Fts5NearTrimmer aStatic[4];
+  Fts5NearTrimmer *a = aStatic;
+  Fts5ExprPhrase **apPhrase = pNear->apPhrase;
+
+  int i;
+  int rc = *pRc;
+  int bMatch;
+
+  assert( pNear->nPhrase>1 );
+
+  /* If the aStatic[] array is not large enough, allocate a large array
+  ** using sqlite3_malloc(). This approach could be improved upon. */
+  if( pNear->nPhrase>(sizeof(aStatic) / sizeof(aStatic[0])) ){
+    int nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase;
+    a = (Fts5NearTrimmer*)sqlite3Fts5MallocZero(&rc, nByte);
+  }else{
+    memset(aStatic, 0, sizeof(aStatic));
+  }
+  if( rc!=SQLITE_OK ){
+    *pRc = rc;
+    return 0;
+  }
+
+  /* Initialize a lookahead iterator for each phrase. After passing the
+  ** buffer and buffer size to the lookaside-reader init function, zero
+  ** the phrase poslist buffer. The new poslist for the phrase (containing
+  ** the same entries as the original with some entries removed on account 
+  ** of the NEAR constraint) is written over the original even as it is
+  ** being read. This is safe as the entries for the new poslist are a
+  ** subset of the old, so it is not possible for data yet to be read to
+  ** be overwritten.  */
+  for(i=0; i<pNear->nPhrase; i++){
+    Fts5Buffer *pPoslist = &apPhrase[i]->poslist;
+    fts5LookaheadReaderInit(pPoslist->p, pPoslist->n, &a[i].reader);
+    pPoslist->n = 0;
+    a[i].pOut = pPoslist;
+  }
+
+  while( 1 ){
+    int iAdv;
+    i64 iMin;
+    i64 iMax;
+
+    /* This block advances the phrase iterators until they point to a set of
+    ** entries that together comprise a match.  */
+    iMax = a[0].reader.iPos;
+    do {
+      bMatch = 1;
+      for(i=0; i<pNear->nPhrase; i++){
+        Fts5LookaheadReader *pPos = &a[i].reader;
+        iMin = iMax - pNear->apPhrase[i]->nTerm - pNear->nNear;
+        if( pPos->iPos<iMin || pPos->iPos>iMax ){
+          bMatch = 0;
+          while( pPos->iPos<iMin ){
+            if( fts5LookaheadReaderNext(pPos) ) goto ismatch_out;
+          }
+          if( pPos->iPos>iMax ) iMax = pPos->iPos;
+        }
+      }
+    }while( bMatch==0 );
+
+    /* Add an entry to each output position list */
+    for(i=0; i<pNear->nPhrase; i++){
+      i64 iPos = a[i].reader.iPos;
+      Fts5PoslistWriter *pWriter = &a[i].writer;
+      if( a[i].pOut->n==0 || iPos!=pWriter->iPrev ){
+        sqlite3Fts5PoslistWriterAppend(a[i].pOut, pWriter, iPos);
+      }
+    }
+
+    iAdv = 0;
+    iMin = a[0].reader.iLookahead;
+    for(i=0; i<pNear->nPhrase; i++){
+      if( a[i].reader.iLookahead < iMin ){
+        iMin = a[i].reader.iLookahead;
+        iAdv = i;
+      }
+    }
+    if( fts5LookaheadReaderNext(&a[iAdv].reader) ) goto ismatch_out;
+  }
+
+  ismatch_out: {
+    int bRet = a[0].pOut->n>0;
+    *pRc = rc;
+    if( a!=aStatic ) sqlite3_free(a);
+    return bRet;
+  }
+}
+
+/*
+** Advance the first term iterator in the first phrase of pNear. Set output
+** variable *pbEof to true if it reaches EOF or if an error occurs.
+**
+** Return SQLITE_OK if successful, or an SQLite error code if an error
+** occurs.
+*/
+static int fts5ExprNearAdvanceFirst(
+  Fts5Expr *pExpr,                /* Expression pPhrase belongs to */
+  Fts5ExprNode *pNode,            /* FTS5_STRING or FTS5_TERM node */
+  int bFromValid,
+  i64 iFrom 
+){
+  Fts5ExprTerm *pTerm = &pNode->pNear->apPhrase[0]->aTerm[0];
+  int rc = SQLITE_OK;
+
+  if( pTerm->pSynonym ){
+    int bEof = 1;
+    Fts5ExprTerm *p;
+
+    /* Find the firstest rowid any synonym points to. */
+    i64 iRowid = fts5ExprSynonymRowid(pTerm, pExpr->bDesc, 0);
+
+    /* Advance each iterator that currently points to iRowid. Or, if iFrom
+    ** is valid - each iterator that points to a rowid before iFrom.  */
+    for(p=pTerm; p; p=p->pSynonym){
+      if( sqlite3Fts5IterEof(p->pIter)==0 ){
+        i64 ii = sqlite3Fts5IterRowid(p->pIter);
+        if( ii==iRowid 
+         || (bFromValid && ii!=iFrom && (ii>iFrom)==pExpr->bDesc) 
+        ){
+          if( bFromValid ){
+            rc = sqlite3Fts5IterNextFrom(p->pIter, iFrom);
+          }else{
+            rc = sqlite3Fts5IterNext(p->pIter);
+          }
+          if( rc!=SQLITE_OK ) break;
+          if( sqlite3Fts5IterEof(p->pIter)==0 ){
+            bEof = 0;
+          }
+        }else{
+          bEof = 0;
+        }
+      }
+    }
+
+    /* Set the EOF flag if either all synonym iterators are at EOF or an
+    ** error has occurred.  */
+    pNode->bEof = (rc || bEof);
+  }else{
+    Fts5IndexIter *pIter = pTerm->pIter;
+
+    assert( Fts5NodeIsString(pNode) );
+    if( bFromValid ){
+      rc = sqlite3Fts5IterNextFrom(pIter, iFrom);
+    }else{
+      rc = sqlite3Fts5IterNext(pIter);
+    }
+
+    pNode->bEof = (rc || sqlite3Fts5IterEof(pIter));
+  }
+
+  return rc;
+}
+
+/*
+** Advance iterator pIter until it points to a value equal to or laster
+** than the initial value of *piLast. If this means the iterator points
+** to a value laster than *piLast, update *piLast to the new lastest value.
+**
+** If the iterator reaches EOF, set *pbEof to true before returning. If
+** an error occurs, set *pRc to an error code. If either *pbEof or *pRc
+** are set, return a non-zero value. Otherwise, return zero.
+*/
+static int fts5ExprAdvanceto(
+  Fts5IndexIter *pIter,           /* Iterator to advance */
+  int bDesc,                      /* True if iterator is "rowid DESC" */
+  i64 *piLast,                    /* IN/OUT: Lastest rowid seen so far */
+  int *pRc,                       /* OUT: Error code */
+  int *pbEof                      /* OUT: Set to true if EOF */
+){
+  i64 iLast = *piLast;
+  i64 iRowid;
+
+  iRowid = sqlite3Fts5IterRowid(pIter);
+  if( (bDesc==0 && iLast>iRowid) || (bDesc && iLast<iRowid) ){
+    int rc = sqlite3Fts5IterNextFrom(pIter, iLast);
+    if( rc || sqlite3Fts5IterEof(pIter) ){
+      *pRc = rc;
+      *pbEof = 1;
+      return 1;
+    }
+    iRowid = sqlite3Fts5IterRowid(pIter);
+    assert( (bDesc==0 && iRowid>=iLast) || (bDesc==1 && iRowid<=iLast) );
+  }
+  *piLast = iRowid;
+
+  return 0;
+}
+
+static int fts5ExprSynonymAdvanceto(
+  Fts5ExprTerm *pTerm,            /* Term iterator to advance */
+  int bDesc,                      /* True if iterator is "rowid DESC" */
+  i64 *piLast,                    /* IN/OUT: Lastest rowid seen so far */
+  int *pRc                        /* OUT: Error code */
+){
+  int rc = SQLITE_OK;
+  i64 iLast = *piLast;
+  Fts5ExprTerm *p;
+  int bEof = 0;
+
+  for(p=pTerm; rc==SQLITE_OK && p; p=p->pSynonym){
+    if( sqlite3Fts5IterEof(p->pIter)==0 ){
+      i64 iRowid = sqlite3Fts5IterRowid(p->pIter);
+      if( (bDesc==0 && iLast>iRowid) || (bDesc && iLast<iRowid) ){
+        rc = sqlite3Fts5IterNextFrom(p->pIter, iLast);
+      }
+    }
+  }
+
+  if( rc!=SQLITE_OK ){
+    *pRc = rc;
+    bEof = 1;
+  }else{
+    *piLast = fts5ExprSynonymRowid(pTerm, bDesc, &bEof);
+  }
+  return bEof;
+}
+
+
+static int fts5ExprNearTest(
+  int *pRc,
+  Fts5Expr *pExpr,                /* Expression that pNear is a part of */
+  Fts5ExprNode *pNode             /* The "NEAR" node (FTS5_STRING) */
+){
+  Fts5ExprNearset *pNear = pNode->pNear;
+  int rc = *pRc;
+  int i;
+
+  /* Check that each phrase in the nearset matches the current row.
+  ** Populate the pPhrase->poslist buffers at the same time. If any
+  ** phrase is not a match, break out of the loop early.  */
+  for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
+    Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
+    if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym || pNear->pColset ){
+      int bMatch = 0;
+      rc = fts5ExprPhraseIsMatch(pNode, pNear->pColset, pPhrase, &bMatch);
+      if( bMatch==0 ) break;
+    }else{
+      rc = sqlite3Fts5IterPoslistBuffer(
+          pPhrase->aTerm[0].pIter, &pPhrase->poslist
+      );
+    }
+  }
+
+  *pRc = rc;
+  if( i==pNear->nPhrase && (i==1 || fts5ExprNearIsMatch(pRc, pNear)) ){
+    return 1;
+  }
+
+  return 0;
+}
+
+static int fts5ExprTokenTest(
+  Fts5Expr *pExpr,                /* Expression that pNear is a part of */
+  Fts5ExprNode *pNode             /* The "NEAR" node (FTS5_TERM) */
+){
+  /* As this "NEAR" object is actually a single phrase that consists 
+  ** of a single term only, grab pointers into the poslist managed by the
+  ** fts5_index.c iterator object. This is much faster than synthesizing 
+  ** a new poslist the way we have to for more complicated phrase or NEAR
+  ** expressions.  */
+  Fts5ExprNearset *pNear = pNode->pNear;
+  Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
+  Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter;
+  Fts5Colset *pColset = pNear->pColset;
+  int rc;
+
+  assert( pNode->eType==FTS5_TERM );
+  assert( pNear->nPhrase==1 && pPhrase->nTerm==1 );
+  assert( pPhrase->aTerm[0].pSynonym==0 );
+
+  rc = sqlite3Fts5IterPoslist(pIter, pColset, 
+      (const u8**)&pPhrase->poslist.p, &pPhrase->poslist.n, &pNode->iRowid
+  );
+  pNode->bNomatch = (pPhrase->poslist.n==0);
+  return rc;
+}
+
+/*
+** All individual term iterators in pNear are guaranteed to be valid when
+** this function is called. This function checks if all term iterators
+** point to the same rowid, and if not, advances them until they do.
+** If an EOF is reached before this happens, *pbEof is set to true before
+** returning.
+**
+** SQLITE_OK is returned if an error occurs, or an SQLite error code 
+** otherwise. It is not considered an error code if an iterator reaches
+** EOF.
+*/
+static int fts5ExprNearNextMatch(
+  Fts5Expr *pExpr,                /* Expression pPhrase belongs to */
+  Fts5ExprNode *pNode
+){
+  Fts5ExprNearset *pNear = pNode->pNear;
+  Fts5ExprPhrase *pLeft = pNear->apPhrase[0];
+  int rc = SQLITE_OK;
+  i64 iLast;                      /* Lastest rowid any iterator points to */
+  int i, j;                       /* Phrase and token index, respectively */
+  int bMatch;                     /* True if all terms are at the same rowid */
+  const int bDesc = pExpr->bDesc;
+
+  /* Check that this node should not be FTS5_TERM */
+  assert( pNear->nPhrase>1 
+       || pNear->apPhrase[0]->nTerm>1 
+       || pNear->apPhrase[0]->aTerm[0].pSynonym
+  );
+
+  /* Initialize iLast, the "lastest" rowid any iterator points to. If the
+  ** iterator skips through rowids in the default ascending order, this means
+  ** the maximum rowid. Or, if the iterator is "ORDER BY rowid DESC", then it
+  ** means the minimum rowid.  */
+  if( pLeft->aTerm[0].pSynonym ){
+    iLast = fts5ExprSynonymRowid(&pLeft->aTerm[0], bDesc, 0);
+  }else{
+    iLast = sqlite3Fts5IterRowid(pLeft->aTerm[0].pIter);
+  }
+
+  do {
+    bMatch = 1;
+    for(i=0; i<pNear->nPhrase; i++){
+      Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
+      for(j=0; j<pPhrase->nTerm; j++){
+        Fts5ExprTerm *pTerm = &pPhrase->aTerm[j];
+        if( pTerm->pSynonym ){
+          i64 iRowid = fts5ExprSynonymRowid(pTerm, bDesc, 0);
+          if( iRowid==iLast ) continue;
+          bMatch = 0;
+          if( fts5ExprSynonymAdvanceto(pTerm, bDesc, &iLast, &rc) ){
+            pNode->bEof = 1;
+            return rc;
+          }
+        }else{
+          Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter;
+          i64 iRowid = sqlite3Fts5IterRowid(pIter);
+          if( iRowid==iLast ) continue;
+          bMatch = 0;
+          if( fts5ExprAdvanceto(pIter, bDesc, &iLast, &rc, &pNode->bEof) ){
+            return rc;
+          }
+        }
+      }
+    }
+  }while( bMatch==0 );
+
+  pNode->iRowid = iLast;
+  pNode->bNomatch = (0==fts5ExprNearTest(&rc, pExpr, pNode));
+
+  return rc;
+}
+
+/*
+** Initialize all term iterators in the pNear object. If any term is found
+** to match no documents at all, return immediately without initializing any
+** further iterators.
+*/
+static int fts5ExprNearInitAll(
+  Fts5Expr *pExpr,
+  Fts5ExprNode *pNode
+){
+  Fts5ExprNearset *pNear = pNode->pNear;
+  int i, j;
+  int rc = SQLITE_OK;
+
+  for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
+    Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
+    for(j=0; j<pPhrase->nTerm; j++){
+      Fts5ExprTerm *pTerm = &pPhrase->aTerm[j];
+      Fts5ExprTerm *p;
+      int bEof = 1;
+
+      for(p=pTerm; p && rc==SQLITE_OK; p=p->pSynonym){
+        if( p->pIter ){
+          sqlite3Fts5IterClose(p->pIter);
+          p->pIter = 0;
+        }
+        rc = sqlite3Fts5IndexQuery(
+            pExpr->pIndex, p->zTerm, strlen(p->zTerm),
+            (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) |
+            (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0),
+            pNear->pColset,
+            &p->pIter
+        );
+        assert( rc==SQLITE_OK || p->pIter==0 );
+        if( p->pIter && 0==sqlite3Fts5IterEof(p->pIter) ){
+          bEof = 0;
+        }
+      }
+
+      if( bEof ){
+        pNode->bEof = 1;
+        return rc;
+      }
+    }
+  }
+
+  return rc;
+}
+
+/* fts5ExprNodeNext() calls fts5ExprNodeNextMatch(). And vice-versa. */
+static int fts5ExprNodeNextMatch(Fts5Expr*, Fts5ExprNode*);
+
+
+/*
+** If pExpr is an ASC iterator, this function returns a value with the
+** same sign as:
+**
+**   (iLhs - iRhs)
+**
+** Otherwise, if this is a DESC iterator, the opposite is returned:
+**
+**   (iRhs - iLhs)
+*/
+static int fts5RowidCmp(
+  Fts5Expr *pExpr,
+  i64 iLhs,
+  i64 iRhs
+){
+  assert( pExpr->bDesc==0 || pExpr->bDesc==1 );
+  if( pExpr->bDesc==0 ){
+    if( iLhs<iRhs ) return -1;
+    return (iLhs > iRhs);
+  }else{
+    if( iLhs>iRhs ) return -1;
+    return (iLhs < iRhs);
+  }
+}
+
+static void fts5ExprSetEof(Fts5ExprNode *pNode){
+  int i;
+  pNode->bEof = 1;
+  for(i=0; i<pNode->nChild; i++){
+    fts5ExprSetEof(pNode->apChild[i]);
+  }
+}
+
+static void fts5ExprNodeZeroPoslist(Fts5ExprNode *pNode){
+  if( pNode->eType==FTS5_STRING || pNode->eType==FTS5_TERM ){
+    Fts5ExprNearset *pNear = pNode->pNear;
+    int i;
+    for(i=0; i<pNear->nPhrase; i++){
+      Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
+      pPhrase->poslist.n = 0;
+    }
+  }else{
+    int i;
+    for(i=0; i<pNode->nChild; i++){
+      fts5ExprNodeZeroPoslist(pNode->apChild[i]);
+    }
+  }
+}
+
+
+static int fts5ExprNodeNext(Fts5Expr*, Fts5ExprNode*, int, i64);
+
+/*
+** Argument pNode is an FTS5_AND node.
+*/
+static int fts5ExprAndNextRowid(
+  Fts5Expr *pExpr,                /* Expression pPhrase belongs to */
+  Fts5ExprNode *pAnd              /* FTS5_AND node to advance */
+){
+  int iChild;
+  i64 iLast = pAnd->iRowid;
+  int rc = SQLITE_OK;
+  int bMatch;
+
+  assert( pAnd->bEof==0 );
+  do {
+    pAnd->bNomatch = 0;
+    bMatch = 1;
+    for(iChild=0; iChild<pAnd->nChild; iChild++){
+      Fts5ExprNode *pChild = pAnd->apChild[iChild];
+      if( 0 && pChild->eType==FTS5_STRING ){
+        /* TODO */
+      }else{
+        int cmp = fts5RowidCmp(pExpr, iLast, pChild->iRowid);
+        if( cmp>0 ){
+          /* Advance pChild until it points to iLast or laster */
+          rc = fts5ExprNodeNext(pExpr, pChild, 1, iLast);
+          if( rc!=SQLITE_OK ) return rc;
+        }
+      }
+
+      /* If the child node is now at EOF, so is the parent AND node. Otherwise,
+      ** the child node is guaranteed to have advanced at least as far as
+      ** rowid iLast. So if it is not at exactly iLast, pChild->iRowid is the
+      ** new lastest rowid seen so far.  */
+      assert( pChild->bEof || fts5RowidCmp(pExpr, iLast, pChild->iRowid)<=0 );
+      if( pChild->bEof ){
+        fts5ExprSetEof(pAnd);
+        bMatch = 1;
+        break;
+      }else if( iLast!=pChild->iRowid ){
+        bMatch = 0;
+        iLast = pChild->iRowid;
+      }
+
+      if( pChild->bNomatch ){
+        pAnd->bNomatch = 1;
+      }
+    }
+  }while( bMatch==0 );
+
+  if( pAnd->bNomatch && pAnd!=pExpr->pRoot ){
+    fts5ExprNodeZeroPoslist(pAnd);
+  }
+  pAnd->iRowid = iLast;
+  return SQLITE_OK;
+}
+
+
+/*
+** Compare the values currently indicated by the two nodes as follows:
+**
+**    res = (*p1) - (*p2)
+**
+** Nodes that point to values that come later in the iteration order are
+** considered to be larger. Nodes at EOF are the largest of all.
+**
+** This means that if the iteration order is ASC, then numerically larger
+** rowids are considered larger. Or if it is the default DESC, numerically
+** smaller rowids are larger.
+*/
+static int fts5NodeCompare(
+  Fts5Expr *pExpr,
+  Fts5ExprNode *p1, 
+  Fts5ExprNode *p2
+){
+  if( p2->bEof ) return -1;
+  if( p1->bEof ) return +1;
+  return fts5RowidCmp(pExpr, p1->iRowid, p2->iRowid);
+}
+
+/*
+** Advance node iterator pNode, part of expression pExpr. If argument
+** bFromValid is zero, then pNode is advanced exactly once. Or, if argument
+** bFromValid is non-zero, then pNode is advanced until it is at or past
+** rowid value iFrom. Whether "past" means "less than" or "greater than"
+** depends on whether this is an ASC or DESC iterator.
+*/
+static int fts5ExprNodeNext(
+  Fts5Expr *pExpr, 
+  Fts5ExprNode *pNode,
+  int bFromValid,
+  i64 iFrom
+){
+  int rc = SQLITE_OK;
+
+  if( pNode->bEof==0 ){
+    switch( pNode->eType ){
+      case FTS5_STRING: {
+        rc = fts5ExprNearAdvanceFirst(pExpr, pNode, bFromValid, iFrom);
+        break;
+      };
+
+      case FTS5_TERM: {
+        Fts5IndexIter *pIter = pNode->pNear->apPhrase[0]->aTerm[0].pIter;
+        if( bFromValid ){
+          rc = sqlite3Fts5IterNextFrom(pIter, iFrom);
+        }else{
+          rc = sqlite3Fts5IterNext(pIter);
+        }
+        if( rc==SQLITE_OK && sqlite3Fts5IterEof(pIter)==0 ){
+          assert( rc==SQLITE_OK );
+          rc = fts5ExprTokenTest(pExpr, pNode);
+        }else{
+          pNode->bEof = 1;
+        }
+        return rc;
+      };
+
+      case FTS5_AND: {
+        Fts5ExprNode *pLeft = pNode->apChild[0];
+        rc = fts5ExprNodeNext(pExpr, pLeft, bFromValid, iFrom);
+        break;
+      }
+
+      case FTS5_OR: {
+        int i;
+        i64 iLast = pNode->iRowid;
+
+        for(i=0; rc==SQLITE_OK && i<pNode->nChild; i++){
+          Fts5ExprNode *p1 = pNode->apChild[i];
+          assert( p1->bEof || fts5RowidCmp(pExpr, p1->iRowid, iLast)>=0 );
+          if( p1->bEof==0 ){
+            if( (p1->iRowid==iLast) 
+             || (bFromValid && fts5RowidCmp(pExpr, p1->iRowid, iFrom)<0)
+            ){
+              rc = fts5ExprNodeNext(pExpr, p1, bFromValid, iFrom);
+            }
+          }
+        }
+
+        break;
+      }
+
+      default: assert( pNode->eType==FTS5_NOT ); {
+        assert( pNode->nChild==2 );
+        rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom);
+        break;
+      }
+    }
+
+    if( rc==SQLITE_OK ){
+      rc = fts5ExprNodeNextMatch(pExpr, pNode);
+    }
+  }
+
+  /* Assert that if bFromValid was true, either:
+  **
+  **   a) an error occurred, or
+  **   b) the node is now at EOF, or
+  **   c) the node is now at or past rowid iFrom.
+  */
+  assert( bFromValid==0 
+      || rc!=SQLITE_OK                                                  /* a */
+      || pNode->bEof                                                    /* b */
+      || pNode->iRowid==iFrom || pExpr->bDesc==(pNode->iRowid<iFrom)    /* c */
+  );
+
+  return rc;
+}
+
+
+/*
+** If pNode currently points to a match, this function returns SQLITE_OK
+** without modifying it. Otherwise, pNode is advanced until it does point
+** to a match or EOF is reached.
+*/
+static int fts5ExprNodeNextMatch(
+  Fts5Expr *pExpr,                /* Expression of which pNode is a part */
+  Fts5ExprNode *pNode             /* Expression node to test */
+){
+  int rc = SQLITE_OK;
+  if( pNode->bEof==0 ){
+    switch( pNode->eType ){
+
+      case FTS5_STRING: {
+        /* Advance the iterators until they all point to the same rowid */
+        rc = fts5ExprNearNextMatch(pExpr, pNode);
+        break;
+      }
+
+      case FTS5_TERM: {
+        rc = fts5ExprTokenTest(pExpr, pNode);
+        break;
+      }
+
+      case FTS5_AND: {
+        rc = fts5ExprAndNextRowid(pExpr, pNode);
+        break;
+      }
+
+      case FTS5_OR: {
+        Fts5ExprNode *pNext = pNode->apChild[0];
+        int i;
+
+        for(i=1; i<pNode->nChild; i++){
+          Fts5ExprNode *pChild = pNode->apChild[i];
+          int cmp = fts5NodeCompare(pExpr, pNext, pChild);
+          if( cmp>0 || (cmp==0 && pChild->bNomatch==0) ){
+            pNext = pChild;
+          }
+        }
+        pNode->iRowid = pNext->iRowid;
+        pNode->bEof = pNext->bEof;
+        pNode->bNomatch = pNext->bNomatch;
+        break;
+      }
+
+      default: assert( pNode->eType==FTS5_NOT ); {
+        Fts5ExprNode *p1 = pNode->apChild[0];
+        Fts5ExprNode *p2 = pNode->apChild[1];
+        assert( pNode->nChild==2 );
+
+        while( rc==SQLITE_OK && p1->bEof==0 ){
+          int cmp = fts5NodeCompare(pExpr, p1, p2);
+          if( cmp>0 ){
+            rc = fts5ExprNodeNext(pExpr, p2, 1, p1->iRowid);
+            cmp = fts5NodeCompare(pExpr, p1, p2);
+          }
+          assert( rc!=SQLITE_OK || cmp<=0 );
+          if( cmp || p2->bNomatch ) break;
+          rc = fts5ExprNodeNext(pExpr, p1, 0, 0);
+        }
+        pNode->bEof = p1->bEof;
+        pNode->iRowid = p1->iRowid;
+        break;
+      }
+    }
+  }
+  return rc;
+}
+
+/*
+** Set node pNode, which is part of expression pExpr, to point to the first
+** match. If there are no matches, set the Node.bEof flag to indicate EOF.
+**
+** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise.
+** It is not an error if there are no matches.
+*/
+static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){
+  int rc = SQLITE_OK;
+  pNode->bEof = 0;
+
+  if( Fts5NodeIsString(pNode) ){
+    /* Initialize all term iterators in the NEAR object. */
+    rc = fts5ExprNearInitAll(pExpr, pNode);
+  }else{
+    int i;
+    for(i=0; i<pNode->nChild && rc==SQLITE_OK; i++){
+      rc = fts5ExprNodeFirst(pExpr, pNode->apChild[i]);
+    }
+    pNode->iRowid = pNode->apChild[0]->iRowid;
+  }
+
+  if( rc==SQLITE_OK ){
+    rc = fts5ExprNodeNextMatch(pExpr, pNode);
+  }
+  return rc;
+}
+
+
+/*
+** Begin iterating through the set of documents in index pIdx matched by
+** the MATCH expression passed as the first argument. If the "bDesc" 
+** parameter is passed a non-zero value, iteration is in descending rowid 
+** order. Or, if it is zero, in ascending order.
+**
+** If iterating in ascending rowid order (bDesc==0), the first document
+** visited is that with the smallest rowid that is larger than or equal
+** to parameter iFirst. Or, if iterating in ascending order (bDesc==1),
+** then the first document visited must have a rowid smaller than or
+** equal to iFirst.
+**
+** Return SQLITE_OK if successful, or an SQLite error code otherwise. It
+** is not considered an error if the query does not match any documents.
+*/
+static int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bDesc){
+  Fts5ExprNode *pRoot = p->pRoot;
+  int rc = SQLITE_OK;
+  if( pRoot ){
+    p->pIndex = pIdx;
+    p->bDesc = bDesc;
+    rc = fts5ExprNodeFirst(p, pRoot);
+
+    /* If not at EOF but the current rowid occurs earlier than iFirst in
+    ** the iteration order, move to document iFirst or later. */
+    if( pRoot->bEof==0 && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0 ){
+      rc = fts5ExprNodeNext(p, pRoot, 1, iFirst);
+    }
+
+    /* If the iterator is not at a real match, skip forward until it is. */
+    while( pRoot->bNomatch && rc==SQLITE_OK && pRoot->bEof==0 ){
+      rc = fts5ExprNodeNext(p, pRoot, 0, 0);
+    }
+  }
+  return rc;
+}
+
+/*
+** Move to the next document 
+**
+** Return SQLITE_OK if successful, or an SQLite error code otherwise. It
+** is not considered an error if the query does not match any documents.
+*/
+static int sqlite3Fts5ExprNext(Fts5Expr *p, i64 iLast){
+  int rc;
+  Fts5ExprNode *pRoot = p->pRoot;
+  do {
+    rc = fts5ExprNodeNext(p, pRoot, 0, 0);
+  }while( pRoot->bNomatch && pRoot->bEof==0 && rc==SQLITE_OK );
+  if( fts5RowidCmp(p, pRoot->iRowid, iLast)>0 ){
+    pRoot->bEof = 1;
+  }
+  return rc;
+}
+
+static int sqlite3Fts5ExprEof(Fts5Expr *p){
+  return (p->pRoot==0 || p->pRoot->bEof);
+}
+
+static i64 sqlite3Fts5ExprRowid(Fts5Expr *p){
+  return p->pRoot->iRowid;
+}
+
+static int fts5ParseStringFromToken(Fts5Token *pToken, char **pz){
+  int rc = SQLITE_OK;
+  *pz = sqlite3Fts5Strndup(&rc, pToken->p, pToken->n);
+  return rc;
+}
+
+/*
+** Free the phrase object passed as the only argument.
+*/
+static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){
+  if( pPhrase ){
+    int i;
+    for(i=0; i<pPhrase->nTerm; i++){
+      Fts5ExprTerm *pSyn;
+      Fts5ExprTerm *pNext;
+      Fts5ExprTerm *pTerm = &pPhrase->aTerm[i];
+      sqlite3_free(pTerm->zTerm);
+      sqlite3Fts5IterClose(pTerm->pIter);
+
+      for(pSyn=pTerm->pSynonym; pSyn; pSyn=pNext){
+        pNext = pSyn->pSynonym;
+        sqlite3Fts5IterClose(pSyn->pIter);
+        sqlite3_free(pSyn);
+      }
+    }
+    if( pPhrase->poslist.nSpace>0 ) fts5BufferFree(&pPhrase->poslist);
+    sqlite3_free(pPhrase);
+  }
+}
+
+/*
+** If argument pNear is NULL, then a new Fts5ExprNearset object is allocated
+** and populated with pPhrase. Or, if pNear is not NULL, phrase pPhrase is
+** appended to it and the results returned.
+**
+** If an OOM error occurs, both the pNear and pPhrase objects are freed and
+** NULL returned.
+*/
+static Fts5ExprNearset *sqlite3Fts5ParseNearset(
+  Fts5Parse *pParse,              /* Parse context */
+  Fts5ExprNearset *pNear,         /* Existing nearset, or NULL */
+  Fts5ExprPhrase *pPhrase         /* Recently parsed phrase */
+){
+  const int SZALLOC = 8;
+  Fts5ExprNearset *pRet = 0;
+
+  if( pParse->rc==SQLITE_OK ){
+    if( pPhrase==0 ){
+      return pNear;
+    }
+    if( pNear==0 ){
+      int nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*);
+      pRet = sqlite3_malloc(nByte);
+      if( pRet==0 ){
+        pParse->rc = SQLITE_NOMEM;
+      }else{
+        memset(pRet, 0, nByte);
+      }
+    }else if( (pNear->nPhrase % SZALLOC)==0 ){
+      int nNew = pNear->nPhrase + SZALLOC;
+      int nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*);
+
+      pRet = (Fts5ExprNearset*)sqlite3_realloc(pNear, nByte);
+      if( pRet==0 ){
+        pParse->rc = SQLITE_NOMEM;
+      }
+    }else{
+      pRet = pNear;
+    }
+  }
+
+  if( pRet==0 ){
+    assert( pParse->rc!=SQLITE_OK );
+    sqlite3Fts5ParseNearsetFree(pNear);
+    sqlite3Fts5ParsePhraseFree(pPhrase);
+  }else{
+    pRet->apPhrase[pRet->nPhrase++] = pPhrase;
+  }
+  return pRet;
+}
+
+typedef struct TokenCtx TokenCtx;
+struct TokenCtx {
+  Fts5ExprPhrase *pPhrase;
+  int rc;
+};
+
+/*
+** Callback for tokenizing terms used by ParseTerm().
+*/
+static int fts5ParseTokenize(
+  void *pContext,                 /* Pointer to Fts5InsertCtx object */
+  int tflags,                     /* Mask of FTS5_TOKEN_* flags */
+  const char *pToken,             /* Buffer containing token */
+  int nToken,                     /* Size of token in bytes */
+  int iUnused1,                   /* Start offset of token */
+  int iUnused2                    /* End offset of token */
+){
+  int rc = SQLITE_OK;
+  const int SZALLOC = 8;
+  TokenCtx *pCtx = (TokenCtx*)pContext;
+  Fts5ExprPhrase *pPhrase = pCtx->pPhrase;
+
+  /* If an error has already occurred, this is a no-op */
+  if( pCtx->rc!=SQLITE_OK ) return pCtx->rc;
+
+  assert( pPhrase==0 || pPhrase->nTerm>0 );
+  if( pPhrase && (tflags & FTS5_TOKEN_COLOCATED) ){
+    Fts5ExprTerm *pSyn;
+    int nByte = sizeof(Fts5ExprTerm) + nToken+1;
+    pSyn = (Fts5ExprTerm*)sqlite3_malloc(nByte);
+    if( pSyn==0 ){
+      rc = SQLITE_NOMEM;
+    }else{
+      memset(pSyn, 0, nByte);
+      pSyn->zTerm = (char*)&pSyn[1];
+      memcpy(pSyn->zTerm, pToken, nToken);
+      pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym;
+      pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn;
+    }
+  }else{
+    Fts5ExprTerm *pTerm;
+    if( pPhrase==0 || (pPhrase->nTerm % SZALLOC)==0 ){
+      Fts5ExprPhrase *pNew;
+      int nNew = SZALLOC + (pPhrase ? pPhrase->nTerm : 0);
+
+      pNew = (Fts5ExprPhrase*)sqlite3_realloc(pPhrase, 
+          sizeof(Fts5ExprPhrase) + sizeof(Fts5ExprTerm) * nNew
+      );
+      if( pNew==0 ){
+        rc = SQLITE_NOMEM;
+      }else{
+        if( pPhrase==0 ) memset(pNew, 0, sizeof(Fts5ExprPhrase));
+        pCtx->pPhrase = pPhrase = pNew;
+        pNew->nTerm = nNew - SZALLOC;
+      }
+    }
+
+    if( rc==SQLITE_OK ){
+      pTerm = &pPhrase->aTerm[pPhrase->nTerm++];
+      memset(pTerm, 0, sizeof(Fts5ExprTerm));
+      pTerm->zTerm = sqlite3Fts5Strndup(&rc, pToken, nToken);
+    }
+  }
+
+  pCtx->rc = rc;
+  return rc;
+}
+
+
+/*
+** Free the phrase object passed as the only argument.
+*/
+static void sqlite3Fts5ParsePhraseFree(Fts5ExprPhrase *pPhrase){
+  fts5ExprPhraseFree(pPhrase);
+}
+
+/*
+** Free the phrase object passed as the second argument.
+*/
+static void sqlite3Fts5ParseNearsetFree(Fts5ExprNearset *pNear){
+  if( pNear ){
+    int i;
+    for(i=0; i<pNear->nPhrase; i++){
+      fts5ExprPhraseFree(pNear->apPhrase[i]);
+    }
+    sqlite3_free(pNear->pColset);
+    sqlite3_free(pNear);
+  }
+}
+
+static void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p){
+  assert( pParse->pExpr==0 );
+  pParse->pExpr = p;
+}
+
+/*
+** This function is called by the parser to process a string token. The
+** string may or may not be quoted. In any case it is tokenized and a
+** phrase object consisting of all tokens returned.
+*/
+static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
+  Fts5Parse *pParse,              /* Parse context */
+  Fts5ExprPhrase *pAppend,        /* Phrase to append to */
+  Fts5Token *pToken,              /* String to tokenize */
+  int bPrefix                     /* True if there is a trailing "*" */
+){
+  Fts5Config *pConfig = pParse->pConfig;
+  TokenCtx sCtx;                  /* Context object passed to callback */
+  int rc;                         /* Tokenize return code */
+  char *z = 0;
+
+  memset(&sCtx, 0, sizeof(TokenCtx));
+  sCtx.pPhrase = pAppend;
+
+  rc = fts5ParseStringFromToken(pToken, &z);
+  if( rc==SQLITE_OK ){
+    int flags = FTS5_TOKENIZE_QUERY | (bPrefix ? FTS5_TOKENIZE_QUERY : 0);
+    int n;
+    sqlite3Fts5Dequote(z);
+    n = strlen(z);
+    rc = sqlite3Fts5Tokenize(pConfig, flags, z, n, &sCtx, fts5ParseTokenize);
+  }
+  sqlite3_free(z);
+  if( rc || (rc = sCtx.rc) ){
+    pParse->rc = rc;
+    fts5ExprPhraseFree(sCtx.pPhrase);
+    sCtx.pPhrase = 0;
+  }else if( sCtx.pPhrase ){
+
+    if( pAppend==0 ){
+      if( (pParse->nPhrase % 8)==0 ){
+        int nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8);
+        Fts5ExprPhrase **apNew;
+        apNew = (Fts5ExprPhrase**)sqlite3_realloc(pParse->apPhrase, nByte);
+        if( apNew==0 ){
+          pParse->rc = SQLITE_NOMEM;
+          fts5ExprPhraseFree(sCtx.pPhrase);
+          return 0;
+        }
+        pParse->apPhrase = apNew;
+      }
+      pParse->nPhrase++;
+    }
+
+    pParse->apPhrase[pParse->nPhrase-1] = sCtx.pPhrase;
+    assert( sCtx.pPhrase->nTerm>0 );
+    sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = bPrefix;
+  }
+
+  return sCtx.pPhrase;
+}
+
+/*
+** Create a new FTS5 expression by cloning phrase iPhrase of the
+** expression passed as the second argument.
+*/
+static int sqlite3Fts5ExprClonePhrase(
+  Fts5Config *pConfig,
+  Fts5Expr *pExpr, 
+  int iPhrase, 
+  Fts5Expr **ppNew
+){
+  int rc = SQLITE_OK;             /* Return code */
+  Fts5ExprPhrase *pOrig;          /* The phrase extracted from pExpr */
+  int i;                          /* Used to iterate through phrase terms */
+
+  Fts5Expr *pNew = 0;             /* Expression to return via *ppNew */
+
+  TokenCtx sCtx = {0,0};          /* Context object for fts5ParseTokenize */
+
+
+  pOrig = pExpr->apExprPhrase[iPhrase];
+
+  pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
+  if( rc==SQLITE_OK ){
+    pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc, 
+        sizeof(Fts5ExprPhrase*));
+  }
+  if( rc==SQLITE_OK ){
+    pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc, 
+        sizeof(Fts5ExprNode));
+  }
+  if( rc==SQLITE_OK ){
+    pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc, 
+        sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*));
+  }
+
+  for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){
+    int tflags = 0;
+    Fts5ExprTerm *p;
+    for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){
+      const char *zTerm = p->zTerm;
+      rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, strlen(zTerm), 0, 0);
+      tflags = FTS5_TOKEN_COLOCATED;
+    }
+    if( rc==SQLITE_OK ){
+      sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
+    }
+  }
+
+  if( rc==SQLITE_OK ){
+    /* All the allocations succeeded. Put the expression object together. */
+    pNew->pIndex = pExpr->pIndex;
+    pNew->nPhrase = 1;
+    pNew->apExprPhrase[0] = sCtx.pPhrase;
+    pNew->pRoot->pNear->apPhrase[0] = sCtx.pPhrase;
+    pNew->pRoot->pNear->nPhrase = 1;
+    sCtx.pPhrase->pNode = pNew->pRoot;
+
+    if( pOrig->nTerm==1 && pOrig->aTerm[0].pSynonym==0 ){
+      pNew->pRoot->eType = FTS5_TERM;
+    }else{
+      pNew->pRoot->eType = FTS5_STRING;
+    }
+  }else{
+    sqlite3Fts5ExprFree(pNew);
+    fts5ExprPhraseFree(sCtx.pPhrase);
+    pNew = 0;
+  }
+
+  *ppNew = pNew;
+  return rc;
+}
+
+
+/*
+** Token pTok has appeared in a MATCH expression where the NEAR operator
+** is expected. If token pTok does not contain "NEAR", store an error
+** in the pParse object.
+*/
+static void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token *pTok){
+  if( pTok->n!=4 || memcmp("NEAR", pTok->p, 4) ){
+    sqlite3Fts5ParseError(
+        pParse, "fts5: syntax error near \"%.*s\"", pTok->n, pTok->p
+    );
+  }
+}
+
+static void sqlite3Fts5ParseSetDistance(
+  Fts5Parse *pParse, 
+  Fts5ExprNearset *pNear,
+  Fts5Token *p
+){
+  int nNear = 0;
+  int i;
+  if( p->n ){
+    for(i=0; i<p->n; i++){
+      char c = (char)p->p[i];
+      if( c<'0' || c>'9' ){
+        sqlite3Fts5ParseError(
+            pParse, "expected integer, got \"%.*s\"", p->n, p->p
+        );
+        return;
+      }
+      nNear = nNear * 10 + (p->p[i] - '0');
+    }
+  }else{
+    nNear = FTS5_DEFAULT_NEARDIST;
+  }
+  pNear->nNear = nNear;
+}
+
+/*
+** The second argument passed to this function may be NULL, or it may be
+** an existing Fts5Colset object. This function returns a pointer to
+** a new colset object containing the contents of (p) with new value column
+** number iCol appended. 
+**
+** If an OOM error occurs, store an error code in pParse and return NULL.
+** The old colset object (if any) is not freed in this case.
+*/
+static Fts5Colset *fts5ParseColset(
+  Fts5Parse *pParse,              /* Store SQLITE_NOMEM here if required */
+  Fts5Colset *p,                  /* Existing colset object */
+  int iCol                        /* New column to add to colset object */
+){
+  int nCol = p ? p->nCol : 0;     /* Num. columns already in colset object */
+  Fts5Colset *pNew;               /* New colset object to return */
+
+  assert( pParse->rc==SQLITE_OK );
+  assert( iCol>=0 && iCol<pParse->pConfig->nCol );
+
+  pNew = sqlite3_realloc(p, sizeof(Fts5Colset) + sizeof(int)*nCol);
+  if( pNew==0 ){
+    pParse->rc = SQLITE_NOMEM;
+  }else{
+    int *aiCol = pNew->aiCol;
+    int i, j;
+    for(i=0; i<nCol; i++){
+      if( aiCol[i]==iCol ) return pNew;
+      if( aiCol[i]>iCol ) break;
+    }
+    for(j=nCol; j>i; j--){
+      aiCol[j] = aiCol[j-1];
+    }
+    aiCol[i] = iCol;
+    pNew->nCol = nCol+1;
+
+#ifndef NDEBUG
+    /* Check that the array is in order and contains no duplicate entries. */
+    for(i=1; i<pNew->nCol; i++) assert( pNew->aiCol[i]>pNew->aiCol[i-1] );
+#endif
+  }
+
+  return pNew;
+}
+
+static Fts5Colset *sqlite3Fts5ParseColset(
+  Fts5Parse *pParse,              /* Store SQLITE_NOMEM here if required */
+  Fts5Colset *pColset,            /* Existing colset object */
+  Fts5Token *p
+){
+  Fts5Colset *pRet = 0;
+  int iCol;
+  char *z;                        /* Dequoted copy of token p */
+
+  z = sqlite3Fts5Strndup(&pParse->rc, p->p, p->n);
+  if( pParse->rc==SQLITE_OK ){
+    Fts5Config *pConfig = pParse->pConfig;
+    sqlite3Fts5Dequote(z);
+    for(iCol=0; iCol<pConfig->nCol; iCol++){
+      if( 0==sqlite3_stricmp(pConfig->azCol[iCol], z) ) break;
+    }
+    if( iCol==pConfig->nCol ){
+      sqlite3Fts5ParseError(pParse, "no such column: %s", z);
+    }else{
+      pRet = fts5ParseColset(pParse, pColset, iCol);
+    }
+    sqlite3_free(z);
+  }
+
+  if( pRet==0 ){
+    assert( pParse->rc!=SQLITE_OK );
+    sqlite3_free(pColset);
+  }
+
+  return pRet;
+}
+
+static void sqlite3Fts5ParseSetColset(
+  Fts5Parse *pParse, 
+  Fts5ExprNearset *pNear, 
+  Fts5Colset *pColset 
+){
+  if( pNear ){
+    pNear->pColset = pColset;
+  }else{
+    sqlite3_free(pColset);
+  }
+}
+
+static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){
+  if( p->eType!=FTS5_NOT && pSub->eType==p->eType ){
+    int nByte = sizeof(Fts5ExprNode*) * pSub->nChild;
+    memcpy(&p->apChild[p->nChild], pSub->apChild, nByte);
+    p->nChild += pSub->nChild;
+    sqlite3_free(pSub);
+  }else{
+    p->apChild[p->nChild++] = pSub;
+  }
+}
+
+/*
+** Allocate and return a new expression object. If anything goes wrong (i.e.
+** OOM error), leave an error code in pParse and return NULL.
+*/
+static Fts5ExprNode *sqlite3Fts5ParseNode(
+  Fts5Parse *pParse,              /* Parse context */
+  int eType,                      /* FTS5_STRING, AND, OR or NOT */
+  Fts5ExprNode *pLeft,            /* Left hand child expression */
+  Fts5ExprNode *pRight,           /* Right hand child expression */
+  Fts5ExprNearset *pNear          /* For STRING expressions, the near cluster */
+){
+  Fts5ExprNode *pRet = 0;
+
+  if( pParse->rc==SQLITE_OK ){
+    int nChild = 0;               /* Number of children of returned node */
+    int nByte;                    /* Bytes of space to allocate for this node */
+    assert( (eType!=FTS5_STRING && !pNear)
+         || (eType==FTS5_STRING && !pLeft && !pRight)
+    );
+    if( eType==FTS5_STRING && pNear==0 ) return 0;
+    if( eType!=FTS5_STRING && pLeft==0 ) return pRight;
+    if( eType!=FTS5_STRING && pRight==0 ) return pLeft;
+
+    if( eType==FTS5_NOT ){
+      nChild = 2;
+    }else if( eType==FTS5_AND || eType==FTS5_OR ){
+      nChild = 2;
+      if( pLeft->eType==eType ) nChild += pLeft->nChild-1;
+      if( pRight->eType==eType ) nChild += pRight->nChild-1;
+    }
+
+    nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1);
+    pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte);
+
+    if( pRet ){
+      pRet->eType = eType;
+      pRet->pNear = pNear;
+      if( eType==FTS5_STRING ){
+        int iPhrase;
+        for(iPhrase=0; iPhrase<pNear->nPhrase; iPhrase++){
+          pNear->apPhrase[iPhrase]->pNode = pRet;
+        }
+        if( pNear->nPhrase==1 
+         && pNear->apPhrase[0]->nTerm==1 
+         && pNear->apPhrase[0]->aTerm[0].pSynonym==0
+        ){
+          pRet->eType = FTS5_TERM;
+        }
+      }else{
+        fts5ExprAddChildren(pRet, pLeft);
+        fts5ExprAddChildren(pRet, pRight);
+      }
+    }
+  }
+
+  if( pRet==0 ){
+    assert( pParse->rc!=SQLITE_OK );
+    sqlite3Fts5ParseNodeFree(pLeft);
+    sqlite3Fts5ParseNodeFree(pRight);
+    sqlite3Fts5ParseNearsetFree(pNear);
+  }
+  return pRet;
+}
+
+static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
+  int nByte = 0;
+  Fts5ExprTerm *p;
+  char *zQuoted;
+
+  /* Determine the maximum amount of space required. */
+  for(p=pTerm; p; p=p->pSynonym){
+    nByte += strlen(pTerm->zTerm) * 2 + 3 + 2;
+  }
+  zQuoted = sqlite3_malloc(nByte);
+
+  if( zQuoted ){
+    int i = 0;
+    for(p=pTerm; p; p=p->pSynonym){
+      char *zIn = p->zTerm;
+      zQuoted[i++] = '"';
+      while( *zIn ){
+        if( *zIn=='"' ) zQuoted[i++] = '"';
+        zQuoted[i++] = *zIn++;
+      }
+      zQuoted[i++] = '"';
+      if( p->pSynonym ) zQuoted[i++] = '|';
+    }
+    if( pTerm->bPrefix ){
+      zQuoted[i++] = ' ';
+      zQuoted[i++] = '*';
+    }
+    zQuoted[i++] = '\0';
+  }
+  return zQuoted;
+}
+
+static char *fts5PrintfAppend(char *zApp, const char *zFmt, ...){
+  char *zNew;
+  va_list ap;
+  va_start(ap, zFmt);
+  zNew = sqlite3_vmprintf(zFmt, ap);
+  va_end(ap);
+  if( zApp && zNew ){
+    char *zNew2 = sqlite3_mprintf("%s%s", zApp, zNew);
+    sqlite3_free(zNew);
+    zNew = zNew2;
+  }
+  sqlite3_free(zApp);
+  return zNew;
+}
+
+/*
+** Compose a tcl-readable representation of expression pExpr. Return a 
+** pointer to a buffer containing that representation. It is the 
+** responsibility of the caller to at some point free the buffer using 
+** sqlite3_free().
+*/
+static char *fts5ExprPrintTcl(
+  Fts5Config *pConfig, 
+  const char *zNearsetCmd,
+  Fts5ExprNode *pExpr
+){
+  char *zRet = 0;
+  if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){
+    Fts5ExprNearset *pNear = pExpr->pNear;
+    int i; 
+    int iTerm;
+
+    zRet = fts5PrintfAppend(zRet, "%s ", zNearsetCmd);
+    if( zRet==0 ) return 0;
+    if( pNear->pColset ){
+      int *aiCol = pNear->pColset->aiCol;
+      int nCol = pNear->pColset->nCol;
+      if( nCol==1 ){
+        zRet = fts5PrintfAppend(zRet, "-col %d ", aiCol[0]);
+      }else{
+        zRet = fts5PrintfAppend(zRet, "-col {%d", aiCol[0]);
+        for(i=1; i<pNear->pColset->nCol; i++){
+          zRet = fts5PrintfAppend(zRet, " %d", aiCol[i]);
+        }
+        zRet = fts5PrintfAppend(zRet, "} ");
+      }
+      if( zRet==0 ) return 0;
+    }
+
+    if( pNear->nPhrase>1 ){
+      zRet = fts5PrintfAppend(zRet, "-near %d ", pNear->nNear);
+      if( zRet==0 ) return 0;
+    }
+
+    zRet = fts5PrintfAppend(zRet, "--");
+    if( zRet==0 ) return 0;
+
+    for(i=0; i<pNear->nPhrase; i++){
+      Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
+
+      zRet = fts5PrintfAppend(zRet, " {");
+      for(iTerm=0; zRet && iTerm<pPhrase->nTerm; iTerm++){
+        char *zTerm = pPhrase->aTerm[iTerm].zTerm;
+        zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" ", zTerm);
+      }
+
+      if( zRet ) zRet = fts5PrintfAppend(zRet, "}");
+      if( zRet==0 ) return 0;
+    }
+
+  }else{
+    char const *zOp = 0;
+    int i;
+    switch( pExpr->eType ){
+      case FTS5_AND: zOp = "AND"; break;
+      case FTS5_NOT: zOp = "NOT"; break;
+      default: 
+        assert( pExpr->eType==FTS5_OR );
+        zOp = "OR"; 
+        break;
+    }
+
+    zRet = sqlite3_mprintf("%s", zOp);
+    for(i=0; zRet && i<pExpr->nChild; i++){
+      char *z = fts5ExprPrintTcl(pConfig, zNearsetCmd, pExpr->apChild[i]);
+      if( !z ){
+        sqlite3_free(zRet);
+        zRet = 0;
+      }else{
+        zRet = fts5PrintfAppend(zRet, " [%z]", z);
+      }
+    }
+  }
+
+  return zRet;
+}
+
+static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){
+  char *zRet = 0;
+  if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){
+    Fts5ExprNearset *pNear = pExpr->pNear;
+    int i; 
+    int iTerm;
+
+    if( pNear->pColset ){
+      int iCol = pNear->pColset->aiCol[0];
+      zRet = fts5PrintfAppend(zRet, "%s : ", pConfig->azCol[iCol]);
+      if( zRet==0 ) return 0;
+    }
+
+    if( pNear->nPhrase>1 ){
+      zRet = fts5PrintfAppend(zRet, "NEAR(");
+      if( zRet==0 ) return 0;
+    }
+
+    for(i=0; i<pNear->nPhrase; i++){
+      Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
+      if( i!=0 ){
+        zRet = fts5PrintfAppend(zRet, " ");
+        if( zRet==0 ) return 0;
+      }
+      for(iTerm=0; iTerm<pPhrase->nTerm; iTerm++){
+        char *zTerm = fts5ExprTermPrint(&pPhrase->aTerm[iTerm]);
+        if( zTerm ){
+          zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" + ", zTerm);
+          sqlite3_free(zTerm);
+        }
+        if( zTerm==0 || zRet==0 ){
+          sqlite3_free(zRet);
+          return 0;
+        }
+      }
+    }
+
+    if( pNear->nPhrase>1 ){
+      zRet = fts5PrintfAppend(zRet, ", %d)", pNear->nNear);
+      if( zRet==0 ) return 0;
+    }
+
+  }else{
+    char const *zOp = 0;
+    int i;
+
+    switch( pExpr->eType ){
+      case FTS5_AND: zOp = " AND "; break;
+      case FTS5_NOT: zOp = " NOT "; break;
+      default:  
+        assert( pExpr->eType==FTS5_OR );
+        zOp = " OR "; 
+        break;
+    }
+
+    for(i=0; i<pExpr->nChild; i++){
+      char *z = fts5ExprPrint(pConfig, pExpr->apChild[i]);
+      if( z==0 ){
+        sqlite3_free(zRet);
+        zRet = 0;
+      }else{
+        int e = pExpr->apChild[i]->eType;
+        int b = (e!=FTS5_STRING && e!=FTS5_TERM);
+        zRet = fts5PrintfAppend(zRet, "%s%s%z%s", 
+            (i==0 ? "" : zOp),
+            (b?"(":""), z, (b?")":"")
+        );
+      }
+      if( zRet==0 ) break;
+    }
+  }
+
+  return zRet;
+}
+
+/*
+** The implementation of user-defined scalar functions fts5_expr() (bTcl==0)
+** and fts5_expr_tcl() (bTcl!=0).
+*/
+static void fts5ExprFunction(
+  sqlite3_context *pCtx,          /* Function call context */
+  int nArg,                       /* Number of args */
+  sqlite3_value **apVal,          /* Function arguments */
+  int bTcl
+){
+  Fts5Global *pGlobal = (Fts5Global*)sqlite3_user_data(pCtx);
+  sqlite3 *db = sqlite3_context_db_handle(pCtx);
+  const char *zExpr = 0;
+  char *zErr = 0;
+  Fts5Expr *pExpr = 0;
+  int rc;
+  int i;
+
+  const char **azConfig;          /* Array of arguments for Fts5Config */
+  const char *zNearsetCmd = "nearset";
+  int nConfig;                    /* Size of azConfig[] */
+  Fts5Config *pConfig = 0;
+  int iArg = 1;
+
+  if( nArg<1 ){
+    zErr = sqlite3_mprintf("wrong number of arguments to function %s",
+        bTcl ? "fts5_expr_tcl" : "fts5_expr"
+    );
+    sqlite3_result_error(pCtx, zErr, -1);
+    sqlite3_free(zErr);
+    return;
+  }
+
+  if( bTcl && nArg>1 ){
+    zNearsetCmd = (const char*)sqlite3_value_text(apVal[1]);
+    iArg = 2;
+  }
+
+  nConfig = 3 + (nArg-iArg);
+  azConfig = (const char**)sqlite3_malloc(sizeof(char*) * nConfig);
+  if( azConfig==0 ){
+    sqlite3_result_error_nomem(pCtx);
+    return;
+  }
+  azConfig[0] = 0;
+  azConfig[1] = "main";
+  azConfig[2] = "tbl";
+  for(i=3; iArg<nArg; iArg++){
+    azConfig[i++] = (const char*)sqlite3_value_text(apVal[iArg]);
+  }
+
+  zExpr = (const char*)sqlite3_value_text(apVal[0]);
+
+  rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr);
+  if( rc==SQLITE_OK ){
+    rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pExpr, &zErr);
+  }
+  if( rc==SQLITE_OK ){
+    char *zText;
+    if( pExpr->pRoot==0 ){
+      zText = sqlite3_mprintf("");
+    }else if( bTcl ){
+      zText = fts5ExprPrintTcl(pConfig, zNearsetCmd, pExpr->pRoot);
+    }else{
+      zText = fts5ExprPrint(pConfig, pExpr->pRoot);
+    }
+    if( zText==0 ){
+      rc = SQLITE_NOMEM;
+    }else{
+      sqlite3_result_text(pCtx, zText, -1, SQLITE_TRANSIENT);
+      sqlite3_free(zText);
+    }
+  }
+
+  if( rc!=SQLITE_OK ){
+    if( zErr ){
+      sqlite3_result_error(pCtx, zErr, -1);
+      sqlite3_free(zErr);
+    }else{
+      sqlite3_result_error_code(pCtx, rc);
+    }
+  }
+  sqlite3_free((void *)azConfig);
+  sqlite3Fts5ConfigFree(pConfig);
+  sqlite3Fts5ExprFree(pExpr);
+}
+
+static void fts5ExprFunctionHr(
+  sqlite3_context *pCtx,          /* Function call context */
+  int nArg,                       /* Number of args */
+  sqlite3_value **apVal           /* Function arguments */
+){
+  fts5ExprFunction(pCtx, nArg, apVal, 0);
+}
+static void fts5ExprFunctionTcl(
+  sqlite3_context *pCtx,          /* Function call context */
+  int nArg,                       /* Number of args */
+  sqlite3_value **apVal           /* Function arguments */
+){
+  fts5ExprFunction(pCtx, nArg, apVal, 1);
+}
+
+/*
+** The implementation of an SQLite user-defined-function that accepts a
+** single integer as an argument. If the integer is an alpha-numeric 
+** unicode code point, 1 is returned. Otherwise 0.
+*/
+static void fts5ExprIsAlnum(
+  sqlite3_context *pCtx,          /* Function call context */
+  int nArg,                       /* Number of args */
+  sqlite3_value **apVal           /* Function arguments */
+){
+  int iCode;
+  if( nArg!=1 ){
+    sqlite3_result_error(pCtx, 
+        "wrong number of arguments to function fts5_isalnum", -1
+    );
+    return;
+  }
+  iCode = sqlite3_value_int(apVal[0]);
+  sqlite3_result_int(pCtx, sqlite3Fts5UnicodeIsalnum(iCode));
+}
+
+static void fts5ExprFold(
+  sqlite3_context *pCtx,          /* Function call context */
+  int nArg,                       /* Number of args */
+  sqlite3_value **apVal           /* Function arguments */
+){
+  if( nArg!=1 && nArg!=2 ){
+    sqlite3_result_error(pCtx, 
+        "wrong number of arguments to function fts5_fold", -1
+    );
+  }else{
+    int iCode;
+    int bRemoveDiacritics = 0;
+    iCode = sqlite3_value_int(apVal[0]);
+    if( nArg==2 ) bRemoveDiacritics = sqlite3_value_int(apVal[1]);
+    sqlite3_result_int(pCtx, sqlite3Fts5UnicodeFold(iCode, bRemoveDiacritics));
+  }
+}
+
+/*
+** This is called during initialization to register the fts5_expr() scalar
+** UDF with the SQLite handle passed as the only argument.
+*/
+static int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){
+  struct Fts5ExprFunc {
+    const char *z;
+    void (*x)(sqlite3_context*,int,sqlite3_value**);
+  } aFunc[] = {
+    { "fts5_expr",     fts5ExprFunctionHr },
+    { "fts5_expr_tcl", fts5ExprFunctionTcl },
+    { "fts5_isalnum",  fts5ExprIsAlnum },
+    { "fts5_fold",     fts5ExprFold },
+  };
+  int i;
+  int rc = SQLITE_OK;
+  void *pCtx = (void*)pGlobal;
+
+  for(i=0; rc==SQLITE_OK && i<(sizeof(aFunc) / sizeof(aFunc[0])); i++){
+    struct Fts5ExprFunc *p = &aFunc[i];
+    rc = sqlite3_create_function(db, p->z, -1, SQLITE_UTF8, pCtx, p->x, 0, 0);
+  }
+
+  /* Avoid a warning indicating that sqlite3Fts5ParserTrace() is unused */
+#ifndef NDEBUG
+  (void)sqlite3Fts5ParserTrace;
+#endif
+
+  return rc;
+}
+
+/*
+** Return the number of phrases in expression pExpr.
+*/
+static int sqlite3Fts5ExprPhraseCount(Fts5Expr *pExpr){
+  return (pExpr ? pExpr->nPhrase : 0);
+}
+
+/*
+** Return the number of terms in the iPhrase'th phrase in pExpr.
+*/
+static int sqlite3Fts5ExprPhraseSize(Fts5Expr *pExpr, int iPhrase){
+  if( iPhrase<0 || iPhrase>=pExpr->nPhrase ) return 0;
+  return pExpr->apExprPhrase[iPhrase]->nTerm;
+}
+
+/*
+** This function is used to access the current position list for phrase
+** iPhrase.
+*/
+static int sqlite3Fts5ExprPoslist(Fts5Expr *pExpr, int iPhrase, const u8 **pa){
+  int nRet;
+  Fts5ExprPhrase *pPhrase = pExpr->apExprPhrase[iPhrase];
+  Fts5ExprNode *pNode = pPhrase->pNode;
+  if( pNode->bEof==0 && pNode->iRowid==pExpr->pRoot->iRowid ){
+    *pa = pPhrase->poslist.p;
+    nRet = pPhrase->poslist.n;
+  }else{
+    *pa = 0;
+    nRet = 0;
+  }
+  return nRet;
+}
+
+/*
+** 2014 August 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.
+**
+******************************************************************************
+**
+*/
+
+
+
+
+typedef struct Fts5HashEntry Fts5HashEntry;
+
+/*
+** This file contains the implementation of an in-memory hash table used
+** to accumuluate "term -> doclist" content before it is flused to a level-0
+** segment.
+*/
+
+
+struct Fts5Hash {
+  int *pnByte;                    /* Pointer to bytes counter */
+  int nEntry;                     /* Number of entries currently in hash */
+  int nSlot;                      /* Size of aSlot[] array */
+  Fts5HashEntry *pScan;           /* Current ordered scan item */
+  Fts5HashEntry **aSlot;          /* Array of hash slots */
+};
+
+/*
+** Each entry in the hash table is represented by an object of the 
+** following type. Each object, its key (zKey[]) and its current data
+** are stored in a single memory allocation. The position list data 
+** immediately follows the key data in memory.
+**
+** The data that follows the key is in a similar, but not identical format
+** to the doclist data stored in the database. It is:
+**
+**   * Rowid, as a varint
+**   * Position list, without 0x00 terminator.
+**   * Size of previous position list and rowid, as a 4 byte
+**     big-endian integer.
+**
+** iRowidOff:
+**   Offset of last rowid written to data area. Relative to first byte of
+**   structure.
+**
+** nData:
+**   Bytes of data written since iRowidOff.
+*/
+struct Fts5HashEntry {
+  Fts5HashEntry *pHashNext;       /* Next hash entry with same hash-key */
+  Fts5HashEntry *pScanNext;       /* Next entry in sorted order */
+  
+  int nAlloc;                     /* Total size of allocation */
+  int iSzPoslist;                 /* Offset of space for 4-byte poslist size */
+  int nData;                      /* Total bytes of data (incl. structure) */
+  u8 bDel;                        /* Set delete-flag @ iSzPoslist */
+
+  int iCol;                       /* Column of last value written */
+  int iPos;                       /* Position of last value written */
+  i64 iRowid;                     /* Rowid of last value written */
+  char zKey[8];                   /* Nul-terminated entry key */
+};
+
+/*
+** Size of Fts5HashEntry without the zKey[] array.
+*/
+#define FTS5_HASHENTRYSIZE (sizeof(Fts5HashEntry)-8)
+
+
+
+/*
+** Allocate a new hash table.
+*/
+static int sqlite3Fts5HashNew(Fts5Hash **ppNew, int *pnByte){
+  int rc = SQLITE_OK;
+  Fts5Hash *pNew;
+
+  *ppNew = pNew = (Fts5Hash*)sqlite3_malloc(sizeof(Fts5Hash));
+  if( pNew==0 ){
+    rc = SQLITE_NOMEM;
+  }else{
+    int nByte;
+    memset(pNew, 0, sizeof(Fts5Hash));
+    pNew->pnByte = pnByte;
+
+    pNew->nSlot = 1024;
+    nByte = sizeof(Fts5HashEntry*) * pNew->nSlot;
+    pNew->aSlot = (Fts5HashEntry**)sqlite3_malloc(nByte);
+    if( pNew->aSlot==0 ){
+      sqlite3_free(pNew);
+      *ppNew = 0;
+      rc = SQLITE_NOMEM;
+    }else{
+      memset(pNew->aSlot, 0, nByte);
+    }
+  }
+  return rc;
+}
+
+/*
+** Free a hash table object.
+*/
+static void sqlite3Fts5HashFree(Fts5Hash *pHash){
+  if( pHash ){
+    sqlite3Fts5HashClear(pHash);
+    sqlite3_free(pHash->aSlot);
+    sqlite3_free(pHash);
+  }
+}
+
+/*
+** Empty (but do not delete) a hash table.
+*/
+static void sqlite3Fts5HashClear(Fts5Hash *pHash){
+  int i;
+  for(i=0; i<pHash->nSlot; i++){
+    Fts5HashEntry *pNext;
+    Fts5HashEntry *pSlot;
+    for(pSlot=pHash->aSlot[i]; pSlot; pSlot=pNext){
+      pNext = pSlot->pHashNext;
+      sqlite3_free(pSlot);
+    }
+  }
+  memset(pHash->aSlot, 0, pHash->nSlot * sizeof(Fts5HashEntry*));
+  pHash->nEntry = 0;
+}
+
+static unsigned int fts5HashKey(int nSlot, const u8 *p, int n){
+  int i;
+  unsigned int h = 13;
+  for(i=n-1; i>=0; i--){
+    h = (h << 3) ^ h ^ p[i];
+  }
+  return (h % nSlot);
+}
+
+static unsigned int fts5HashKey2(int nSlot, u8 b, const u8 *p, int n){
+  int i;
+  unsigned int h = 13;
+  for(i=n-1; i>=0; i--){
+    h = (h << 3) ^ h ^ p[i];
+  }
+  h = (h << 3) ^ h ^ b;
+  return (h % nSlot);
+}
+
+/*
+** Resize the hash table by doubling the number of slots.
+*/
+static int fts5HashResize(Fts5Hash *pHash){
+  int nNew = pHash->nSlot*2;
+  int i;
+  Fts5HashEntry **apNew;
+  Fts5HashEntry **apOld = pHash->aSlot;
+
+  apNew = (Fts5HashEntry**)sqlite3_malloc(nNew*sizeof(Fts5HashEntry*));
+  if( !apNew ) return SQLITE_NOMEM;
+  memset(apNew, 0, nNew*sizeof(Fts5HashEntry*));
+
+  for(i=0; i<pHash->nSlot; i++){
+    while( apOld[i] ){
+      int iHash;
+      Fts5HashEntry *p = apOld[i];
+      apOld[i] = p->pHashNext;
+      iHash = fts5HashKey(nNew, (u8*)p->zKey, strlen(p->zKey));
+      p->pHashNext = apNew[iHash];
+      apNew[iHash] = p;
+    }
+  }
+
+  sqlite3_free(apOld);
+  pHash->nSlot = nNew;
+  pHash->aSlot = apNew;
+  return SQLITE_OK;
+}
+
+static void fts5HashAddPoslistSize(Fts5HashEntry *p){
+  if( p->iSzPoslist ){
+    u8 *pPtr = (u8*)p;
+    int nSz = (p->nData - p->iSzPoslist - 1);         /* Size in bytes */
+    int nPos = nSz*2 + p->bDel;                       /* Value of nPos field */
+
+    assert( p->bDel==0 || p->bDel==1 );
+    if( nPos<=127 ){
+      pPtr[p->iSzPoslist] = nPos;
+    }else{
+      int nByte = sqlite3Fts5GetVarintLen((u32)nPos);
+      memmove(&pPtr[p->iSzPoslist + nByte], &pPtr[p->iSzPoslist + 1], nSz);
+      sqlite3Fts5PutVarint(&pPtr[p->iSzPoslist], nPos);
+      p->nData += (nByte-1);
+    }
+    p->bDel = 0;
+    p->iSzPoslist = 0;
+  }
+}
+
+static int sqlite3Fts5HashWrite(
+  Fts5Hash *pHash,
+  i64 iRowid,                     /* Rowid for this entry */
+  int iCol,                       /* Column token appears in (-ve -> delete) */
+  int iPos,                       /* Position of token within column */
+  char bByte,                     /* First byte of token */
+  const char *pToken, int nToken  /* Token to add or remove to or from index */
+){
+  unsigned int iHash;
+  Fts5HashEntry *p;
+  u8 *pPtr;
+  int nIncr = 0;                  /* Amount to increment (*pHash->pnByte) by */
+
+  /* Attempt to locate an existing hash entry */
+  iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken);
+  for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
+    if( p->zKey[0]==bByte 
+     && memcmp(&p->zKey[1], pToken, nToken)==0 
+     && p->zKey[nToken+1]==0 
+    ){
+      break;
+    }
+  }
+
+  /* If an existing hash entry cannot be found, create a new one. */
+  if( p==0 ){
+    int nByte = FTS5_HASHENTRYSIZE + (nToken+1) + 1 + 64;
+    if( nByte<128 ) nByte = 128;
+
+    if( (pHash->nEntry*2)>=pHash->nSlot ){
+      int rc = fts5HashResize(pHash);
+      if( rc!=SQLITE_OK ) return rc;
+      iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken);
+    }
+
+    p = (Fts5HashEntry*)sqlite3_malloc(nByte);
+    if( !p ) return SQLITE_NOMEM;
+    memset(p, 0, FTS5_HASHENTRYSIZE);
+    p->nAlloc = nByte;
+    p->zKey[0] = bByte;
+    memcpy(&p->zKey[1], pToken, nToken);
+    assert( iHash==fts5HashKey(pHash->nSlot, (u8*)p->zKey, nToken+1) );
+    p->zKey[nToken+1] = '\0';
+    p->nData = nToken+1 + 1 + FTS5_HASHENTRYSIZE;
+    p->nData += sqlite3Fts5PutVarint(&((u8*)p)[p->nData], iRowid);
+    p->iSzPoslist = p->nData;
+    p->nData += 1;
+    p->iRowid = iRowid;
+    p->pHashNext = pHash->aSlot[iHash];
+    pHash->aSlot[iHash] = p;
+    pHash->nEntry++;
+    nIncr += p->nData;
+  }
+
+  /* Check there is enough space to append a new entry. Worst case scenario
+  ** is:
+  **
+  **     + 9 bytes for a new rowid,
+  **     + 4 byte reserved for the "poslist size" varint.
+  **     + 1 byte for a "new column" byte,
+  **     + 3 bytes for a new column number (16-bit max) as a varint,
+  **     + 5 bytes for the new position offset (32-bit max).
+  */
+  if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){
+    int nNew = p->nAlloc * 2;
+    Fts5HashEntry *pNew;
+    Fts5HashEntry **pp;
+    pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew);
+    if( pNew==0 ) return SQLITE_NOMEM;
+    pNew->nAlloc = nNew;
+    for(pp=&pHash->aSlot[iHash]; *pp!=p; pp=&(*pp)->pHashNext);
+    *pp = pNew;
+    p = pNew;
+  }
+  pPtr = (u8*)p;
+  nIncr -= p->nData;
+
+  /* If this is a new rowid, append the 4-byte size field for the previous
+  ** entry, and the new rowid for this entry.  */
+  if( iRowid!=p->iRowid ){
+    fts5HashAddPoslistSize(p);
+    p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid);
+    p->iSzPoslist = p->nData;
+    p->nData += 1;
+    p->iCol = 0;
+    p->iPos = 0;
+    p->iRowid = iRowid;
+  }
+
+  if( iCol>=0 ){
+    /* Append a new column value, if necessary */
+    assert( iCol>=p->iCol );
+    if( iCol!=p->iCol ){
+      pPtr[p->nData++] = 0x01;
+      p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iCol);
+      p->iCol = iCol;
+      p->iPos = 0;
+    }
+
+    /* Append the new position offset */
+    p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iPos - p->iPos + 2);
+    p->iPos = iPos;
+  }else{
+    /* This is a delete. Set the delete flag. */
+    p->bDel = 1;
+  }
+  nIncr += p->nData;
+
+  *pHash->pnByte += nIncr;
+  return SQLITE_OK;
+}
+
+
+/*
+** Arguments pLeft and pRight point to linked-lists of hash-entry objects,
+** each sorted in key order. This function merges the two lists into a
+** single list and returns a pointer to its first element.
+*/
+static Fts5HashEntry *fts5HashEntryMerge(
+  Fts5HashEntry *pLeft,
+  Fts5HashEntry *pRight
+){
+  Fts5HashEntry *p1 = pLeft;
+  Fts5HashEntry *p2 = pRight;
+  Fts5HashEntry *pRet = 0;
+  Fts5HashEntry **ppOut = &pRet;
+
+  while( p1 || p2 ){
+    if( p1==0 ){
+      *ppOut = p2;
+      p2 = 0;
+    }else if( p2==0 ){
+      *ppOut = p1;
+      p1 = 0;
+    }else{
+      int i = 0;
+      while( p1->zKey[i]==p2->zKey[i] ) i++;
+
+      if( ((u8)p1->zKey[i])>((u8)p2->zKey[i]) ){
+        /* p2 is smaller */
+        *ppOut = p2;
+        ppOut = &p2->pScanNext;
+        p2 = p2->pScanNext;
+      }else{
+        /* p1 is smaller */
+        *ppOut = p1;
+        ppOut = &p1->pScanNext;
+        p1 = p1->pScanNext;
+      }
+      *ppOut = 0;
+    }
+  }
+
+  return pRet;
+}
+
+/*
+** Extract all tokens from hash table iHash and link them into a list
+** in sorted order. The hash table is cleared before returning. It is
+** the responsibility of the caller to free the elements of the returned
+** list.
+*/
+static int fts5HashEntrySort(
+  Fts5Hash *pHash, 
+  const char *pTerm, int nTerm,   /* Query prefix, if any */
+  Fts5HashEntry **ppSorted
+){
+  const int nMergeSlot = 32;
+  Fts5HashEntry **ap;
+  Fts5HashEntry *pList;
+  int iSlot;
+  int i;
+
+  *ppSorted = 0;
+  ap = sqlite3_malloc(sizeof(Fts5HashEntry*) * nMergeSlot);
+  if( !ap ) return SQLITE_NOMEM;
+  memset(ap, 0, sizeof(Fts5HashEntry*) * nMergeSlot);
+
+  for(iSlot=0; iSlot<pHash->nSlot; iSlot++){
+    Fts5HashEntry *pIter;
+    for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){
+      if( pTerm==0 || 0==memcmp(pIter->zKey, pTerm, nTerm) ){
+        Fts5HashEntry *pEntry = pIter;
+        pEntry->pScanNext = 0;
+        for(i=0; ap[i]; i++){
+          pEntry = fts5HashEntryMerge(pEntry, ap[i]);
+          ap[i] = 0;
+        }
+        ap[i] = pEntry;
+      }
+    }
+  }
+
+  pList = 0;
+  for(i=0; i<nMergeSlot; i++){
+    pList = fts5HashEntryMerge(pList, ap[i]);
+  }
+
+  pHash->nEntry = 0;
+  sqlite3_free(ap);
+  *ppSorted = pList;
+  return SQLITE_OK;
+}
+
+/*
+** Query the hash table for a doclist associated with term pTerm/nTerm.
+*/
+static int sqlite3Fts5HashQuery(
+  Fts5Hash *pHash,                /* Hash table to query */
+  const char *pTerm, int nTerm,   /* Query term */
+  const u8 **ppDoclist,           /* OUT: Pointer to doclist for pTerm */
+  int *pnDoclist                  /* OUT: Size of doclist in bytes */
+){
+  unsigned int iHash = fts5HashKey(pHash->nSlot, (const u8*)pTerm, nTerm);
+  Fts5HashEntry *p;
+
+  for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
+    if( memcmp(p->zKey, pTerm, nTerm)==0 && p->zKey[nTerm]==0 ) break;
+  }
+
+  if( p ){
+    fts5HashAddPoslistSize(p);
+    *ppDoclist = (const u8*)&p->zKey[nTerm+1];
+    *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1);
+  }else{
+    *ppDoclist = 0;
+    *pnDoclist = 0;
+  }
+
+  return SQLITE_OK;
+}
+
+static int sqlite3Fts5HashScanInit(
+  Fts5Hash *p,                    /* Hash table to query */
+  const char *pTerm, int nTerm    /* Query prefix */
+){
+  return fts5HashEntrySort(p, pTerm, nTerm, &p->pScan);
+}
+
+static void sqlite3Fts5HashScanNext(Fts5Hash *p){
+  assert( !sqlite3Fts5HashScanEof(p) );
+  p->pScan = p->pScan->pScanNext;
+}
+
+static int sqlite3Fts5HashScanEof(Fts5Hash *p){
+  return (p->pScan==0);
+}
+
+static void sqlite3Fts5HashScanEntry(
+  Fts5Hash *pHash,
+  const char **pzTerm,            /* OUT: term (nul-terminated) */
+  const u8 **ppDoclist,           /* OUT: pointer to doclist */
+  int *pnDoclist                  /* OUT: size of doclist in bytes */
+){
+  Fts5HashEntry *p;
+  if( (p = pHash->pScan) ){
+    int nTerm = strlen(p->zKey);
+    fts5HashAddPoslistSize(p);
+    *pzTerm = p->zKey;
+    *ppDoclist = (const u8*)&p->zKey[nTerm+1];
+    *pnDoclist = p->nData - (FTS5_HASHENTRYSIZE + nTerm + 1);
+  }else{
+    *pzTerm = 0;
+    *ppDoclist = 0;
+    *pnDoclist = 0;
+  }
+}
+
+
+/*
+** 2014 May 31
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** Low level access to the FTS index stored in the database file. The 
+** routines in this file file implement all read and write access to the
+** %_data table. Other parts of the system access this functionality via
+** the interface defined in fts5Int.h.
+*/
+
+
+
+/*
+** Overview:
+**
+** The %_data table contains all the FTS indexes for an FTS5 virtual table.
+** As well as the main term index, there may be up to 31 prefix indexes.
+** The format is similar to FTS3/4, except that:
+**
+**   * all segment b-tree leaf data is stored in fixed size page records 
+**     (e.g. 1000 bytes). A single doclist may span multiple pages. Care is 
+**     taken to ensure it is possible to iterate in either direction through 
+**     the entries in a doclist, or to seek to a specific entry within a 
+**     doclist, without loading it into memory.
+**
+**   * large doclists that span many pages have associated "doclist index"
+**     records that contain a copy of the first rowid on each page spanned by
+**     the doclist. This is used to speed up seek operations, and merges of
+**     large doclists with very small doclists.
+**
+**   * extra fields in the "structure record" record the state of ongoing
+**     incremental merge operations.
+**
+*/
+
+
+#define FTS5_OPT_WORK_UNIT  1000  /* Number of leaf pages per optimize step */
+#define FTS5_WORK_UNIT      64    /* Number of leaf pages in unit of work */
+
+#define FTS5_MIN_DLIDX_SIZE 4     /* Add dlidx if this many empty pages */
+
+#define FTS5_MAIN_PREFIX '0'
+
+#if FTS5_MAX_PREFIX_INDEXES > 31
+# error "FTS5_MAX_PREFIX_INDEXES is too large"
+#endif
+
+/*
+** Details:
+**
+** The %_data table managed by this module,
+**
+**     CREATE TABLE %_data(id INTEGER PRIMARY KEY, block BLOB);
+**
+** , contains the following 5 types of records. See the comments surrounding
+** the FTS5_*_ROWID macros below for a description of how %_data rowids are 
+** assigned to each fo them.
+**
+** 1. Structure Records:
+**
+**   The set of segments that make up an index - the index structure - are
+**   recorded in a single record within the %_data table. The record consists
+**   of a single 32-bit configuration cookie value followed by a list of 
+**   SQLite varints. If the FTS table features more than one index (because
+**   there are one or more prefix indexes), it is guaranteed that all share
+**   the same cookie value.
+**
+**   Immediately following the configuration cookie, the record begins with
+**   three varints:
+**
+**     + number of levels,
+**     + total number of segments on all levels,
+**     + value of write counter.
+**
+**   Then, for each level from 0 to nMax:
+**
+**     + number of input segments in ongoing merge.
+**     + total number of segments in level.
+**     + for each segment from oldest to newest:
+**         + segment id (always > 0)
+**         + first leaf page number (often 1, always greater than 0)
+**         + final leaf page number
+**
+** 2. The Averages Record:
+**
+**   A single record within the %_data table. The data is a list of varints.
+**   The first value is the number of rows in the index. Then, for each column
+**   from left to right, the total number of tokens in the column for all
+**   rows of the table.
+**
+** 3. Segment leaves:
+**
+**   TERM/DOCLIST FORMAT:
+**
+**     Most of each segment leaf is taken up by term/doclist data. The 
+**     general format of term/doclist, starting with the first term
+**     on the leaf page, is:
+**
+**         varint : size of first term
+**         blob:    first term data
+**         doclist: first doclist
+**         zero-or-more {
+**           varint:  number of bytes in common with previous term
+**           varint:  number of bytes of new term data (nNew)
+**           blob:    nNew bytes of new term data
+**           doclist: next doclist
+**         }
+**
+**     doclist format:
+**
+**         varint:  first rowid
+**         poslist: first poslist
+**         zero-or-more {
+**           varint:  rowid delta (always > 0)
+**           poslist: next poslist
+**         }
+**
+**     poslist format:
+**
+**         varint: size of poslist in bytes multiplied by 2, not including
+**                 this field. Plus 1 if this entry carries the "delete" flag.
+**         collist: collist for column 0
+**         zero-or-more {
+**           0x01 byte
+**           varint: column number (I)
+**           collist: collist for column I
+**         }
+**
+**     collist format:
+**
+**         varint: first offset + 2
+**         zero-or-more {
+**           varint: offset delta + 2
+**         }
+**
+**   PAGE FORMAT
+**
+**     Each leaf page begins with a 4-byte header containing 2 16-bit 
+**     unsigned integer fields in big-endian format. They are:
+**
+**       * The byte offset of the first rowid on the page, if it exists
+**         and occurs before the first term (otherwise 0).
+**
+**       * The byte offset of the start of the page footer. If the page
+**         footer is 0 bytes in size, then this field is the same as the
+**         size of the leaf page in bytes.
+**
+**     The page footer consists of a single varint for each term located
+**     on the page. Each varint is the byte offset of the current term
+**     within the page, delta-compressed against the previous value. In
+**     other words, the first varint in the footer is the byte offset of
+**     the first term, the second is the byte offset of the second less that
+**     of the first, and so on.
+**
+**     The term/doclist format described above is accurate if the entire
+**     term/doclist data fits on a single leaf page. If this is not the case,
+**     the format is changed in two ways:
+**
+**       + if the first rowid on a page occurs before the first term, it
+**         is stored as a literal value:
+**
+**             varint:  first rowid
+**
+**       + the first term on each page is stored in the same way as the
+**         very first term of the segment:
+**
+**             varint : size of first term
+**             blob:    first term data
+**
+** 5. Segment doclist indexes:
+**
+**   Doclist indexes are themselves b-trees, however they usually consist of
+**   a single leaf record only. The format of each doclist index leaf page 
+**   is:
+**
+**     * Flags byte. Bits are:
+**         0x01: Clear if leaf is also the root page, otherwise set.
+**
+**     * Page number of fts index leaf page. As a varint.
+**
+**     * First rowid on page indicated by previous field. As a varint.
+**
+**     * A list of varints, one for each subsequent termless page. A 
+**       positive delta if the termless page contains at least one rowid, 
+**       or an 0x00 byte otherwise.
+**
+**   Internal doclist index nodes are:
+**
+**     * Flags byte. Bits are:
+**         0x01: Clear for root page, otherwise set.
+**
+**     * Page number of first child page. As a varint.
+**
+**     * Copy of first rowid on page indicated by previous field. As a varint.
+**
+**     * A list of delta-encoded varints - the first rowid on each subsequent
+**       child page. 
+**
+*/
+
+/*
+** Rowids for the averages and structure records in the %_data table.
+*/
+#define FTS5_AVERAGES_ROWID     1    /* Rowid used for the averages record */
+#define FTS5_STRUCTURE_ROWID   10    /* The structure record */
+
+/*
+** Macros determining the rowids used by segment leaves and dlidx leaves
+** and nodes. All nodes and leaves are stored in the %_data table with large
+** positive rowids.
+**
+** Each segment has a unique non-zero 16-bit id.
+**
+** The rowid for each segment leaf is found by passing the segment id and 
+** the leaf page number to the FTS5_SEGMENT_ROWID macro. Leaves are numbered
+** sequentially starting from 1.
+*/
+#define FTS5_DATA_ID_B     16     /* Max seg id number 65535 */
+#define FTS5_DATA_DLI_B     1     /* Doclist-index flag (1 bit) */
+#define FTS5_DATA_HEIGHT_B  5     /* Max dlidx tree height of 32 */
+#define FTS5_DATA_PAGE_B   31     /* Max page number of 2147483648 */
+
+#define fts5_dri(segid, dlidx, height, pgno) (                                 \
+ ((i64)(segid)  << (FTS5_DATA_PAGE_B+FTS5_DATA_HEIGHT_B+FTS5_DATA_DLI_B)) +    \
+ ((i64)(dlidx)  << (FTS5_DATA_PAGE_B + FTS5_DATA_HEIGHT_B)) +                  \
+ ((i64)(height) << (FTS5_DATA_PAGE_B)) +                                       \
+ ((i64)(pgno))                                                                 \
+)
+
+#define FTS5_SEGMENT_ROWID(segid, pgno)       fts5_dri(segid, 0, 0, pgno)
+#define FTS5_DLIDX_ROWID(segid, height, pgno) fts5_dri(segid, 1, height, pgno)
+
+/*
+** Maximum segments permitted in a single index 
+*/
+#define FTS5_MAX_SEGMENT 2000
+
+#ifdef SQLITE_DEBUG
+static int sqlite3Fts5Corrupt() { return SQLITE_CORRUPT_VTAB; }
+#endif
+
+
+/*
+** Each time a blob is read from the %_data table, it is padded with this
+** many zero bytes. This makes it easier to decode the various record formats
+** without overreading if the records are corrupt.
+*/
+#define FTS5_DATA_ZERO_PADDING 8
+#define FTS5_DATA_PADDING 20
+
+typedef struct Fts5Data Fts5Data;
+typedef struct Fts5DlidxIter Fts5DlidxIter;
+typedef struct Fts5DlidxLvl Fts5DlidxLvl;
+typedef struct Fts5DlidxWriter Fts5DlidxWriter;
+typedef struct Fts5PageWriter Fts5PageWriter;
+typedef struct Fts5SegIter Fts5SegIter;
+typedef struct Fts5DoclistIter Fts5DoclistIter;
+typedef struct Fts5SegWriter Fts5SegWriter;
+typedef struct Fts5Structure Fts5Structure;
+typedef struct Fts5StructureLevel Fts5StructureLevel;
+typedef struct Fts5StructureSegment Fts5StructureSegment;
+
+struct Fts5Data {
+  u8 *p;                          /* Pointer to buffer containing record */
+  int nn;                         /* Size of record in bytes */
+  int szLeaf;                     /* Size of leaf without page-index */
+};
+
+/*
+** One object per %_data table.
+*/
+struct Fts5Index {
+  Fts5Config *pConfig;            /* Virtual table configuration */
+  char *zDataTbl;                 /* Name of %_data table */
+  int nWorkUnit;                  /* Leaf pages in a "unit" of work */
+
+  /*
+  ** Variables related to the accumulation of tokens and doclists within the
+  ** in-memory hash tables before they are flushed to disk.
+  */
+  Fts5Hash *pHash;                /* Hash table for in-memory data */
+  int nMaxPendingData;            /* Max pending data before flush to disk */
+  int nPendingData;               /* Current bytes of pending data */
+  i64 iWriteRowid;                /* Rowid for current doc being written */
+  int bDelete;                    /* Current write is a delete */
+
+  /* Error state. */
+  int rc;                         /* Current error code */
+
+  /* State used by the fts5DataXXX() functions. */
+  sqlite3_blob *pReader;          /* RO incr-blob open on %_data table */
+  sqlite3_stmt *pWriter;          /* "INSERT ... %_data VALUES(?,?)" */
+  sqlite3_stmt *pDeleter;         /* "DELETE FROM %_data ... id>=? AND id<=?" */
+  sqlite3_stmt *pIdxWriter;       /* "INSERT ... %_idx VALUES(?,?,?,?)" */
+  sqlite3_stmt *pIdxDeleter;      /* "DELETE FROM %_idx WHERE segid=? */
+  sqlite3_stmt *pIdxSelect;
+  int nRead;                      /* Total number of blocks read */
+};
+
+struct Fts5DoclistIter {
+  u8 *aEof;                       /* Pointer to 1 byte past end of doclist */
+
+  /* Output variables. aPoslist==0 at EOF */
+  i64 iRowid;
+  u8 *aPoslist;
+  int nPoslist;
+  int nSize;
+};
+
+/*
+** The contents of the "structure" record for each index are represented
+** using an Fts5Structure record in memory. Which uses instances of the 
+** other Fts5StructureXXX types as components.
+*/
+struct Fts5StructureSegment {
+  int iSegid;                     /* Segment id */
+  int pgnoFirst;                  /* First leaf page number in segment */
+  int pgnoLast;                   /* Last leaf page number in segment */
+};
+struct Fts5StructureLevel {
+  int nMerge;                     /* Number of segments in incr-merge */
+  int nSeg;                       /* Total number of segments on level */
+  Fts5StructureSegment *aSeg;     /* Array of segments. aSeg[0] is oldest. */
+};
+struct Fts5Structure {
+  int nRef;                       /* Object reference count */
+  u64 nWriteCounter;              /* Total leaves written to level 0 */
+  int nSegment;                   /* Total segments in this structure */
+  int nLevel;                     /* Number of levels in this index */
+  Fts5StructureLevel aLevel[1];   /* Array of nLevel level objects */
+};
+
+/*
+** An object of type Fts5SegWriter is used to write to segments.
+*/
+struct Fts5PageWriter {
+  int pgno;                       /* Page number for this page */
+  int iPrevPgidx;                 /* Previous value written into pgidx */
+  Fts5Buffer buf;                 /* Buffer containing leaf data */
+  Fts5Buffer pgidx;               /* Buffer containing page-index */
+  Fts5Buffer term;                /* Buffer containing previous term on page */
+};
+struct Fts5DlidxWriter {
+  int pgno;                       /* Page number for this page */
+  int bPrevValid;                 /* True if iPrev is valid */
+  i64 iPrev;                      /* Previous rowid value written to page */
+  Fts5Buffer buf;                 /* Buffer containing page data */
+};
+struct Fts5SegWriter {
+  int iSegid;                     /* Segid to write to */
+  Fts5PageWriter writer;          /* PageWriter object */
+  i64 iPrevRowid;                 /* Previous rowid written to current leaf */
+  u8 bFirstRowidInDoclist;        /* True if next rowid is first in doclist */
+  u8 bFirstRowidInPage;           /* True if next rowid is first in page */
+  /* TODO1: Can use (writer.pgidx.n==0) instead of bFirstTermInPage */
+  u8 bFirstTermInPage;            /* True if next term will be first in leaf */
+  int nLeafWritten;               /* Number of leaf pages written */
+  int nEmpty;                     /* Number of contiguous term-less nodes */
+
+  int nDlidx;                     /* Allocated size of aDlidx[] array */
+  Fts5DlidxWriter *aDlidx;        /* Array of Fts5DlidxWriter objects */
+
+  /* Values to insert into the %_idx table */
+  Fts5Buffer btterm;              /* Next term to insert into %_idx table */
+  int iBtPage;                    /* Page number corresponding to btterm */
+};
+
+/*
+** Object for iterating through the merged results of one or more segments,
+** visiting each term/rowid pair in the merged data.
+**
+** nSeg is always a power of two greater than or equal to the number of
+** segments that this object is merging data from. Both the aSeg[] and
+** aFirst[] arrays are sized at nSeg entries. The aSeg[] array is padded
+** with zeroed objects - these are handled as if they were iterators opened
+** on empty segments.
+**
+** The results of comparing segments aSeg[N] and aSeg[N+1], where N is an
+** even number, is stored in aFirst[(nSeg+N)/2]. The "result" of the 
+** comparison in this context is the index of the iterator that currently
+** points to the smaller term/rowid combination. Iterators at EOF are
+** considered to be greater than all other iterators.
+**
+** aFirst[1] contains the index in aSeg[] of the iterator that points to
+** the smallest key overall. aFirst[0] is unused. 
+*/
+
+typedef struct Fts5CResult Fts5CResult;
+struct Fts5CResult {
+  u16 iFirst;                     /* aSeg[] index of firstest iterator */
+  u8 bTermEq;                     /* True if the terms are equal */
+};
+
+/*
+** Object for iterating through a single segment, visiting each term/rowid
+** pair in the segment.
+**
+** pSeg:
+**   The segment to iterate through.
+**
+** iLeafPgno:
+**   Current leaf page number within segment.
+**
+** iLeafOffset:
+**   Byte offset within the current leaf that is the first byte of the 
+**   position list data (one byte passed the position-list size field).
+**   rowid field of the current entry. Usually this is the size field of the
+**   position list data. The exception is if the rowid for the current entry 
+**   is the last thing on the leaf page.
+**
+** pLeaf:
+**   Buffer containing current leaf page data. Set to NULL at EOF.
+**
+** iTermLeafPgno, iTermLeafOffset:
+**   Leaf page number containing the last term read from the segment. And
+**   the offset immediately following the term data.
+**
+** flags:
+**   Mask of FTS5_SEGITER_XXX values. Interpreted as follows:
+**
+**   FTS5_SEGITER_ONETERM:
+**     If set, set the iterator to point to EOF after the current doclist 
+**     has been exhausted. Do not proceed to the next term in the segment.
+**
+**   FTS5_SEGITER_REVERSE:
+**     This flag is only ever set if FTS5_SEGITER_ONETERM is also set. If
+**     it is set, iterate through rowid in descending order instead of the
+**     default ascending order.
+**
+** iRowidOffset/nRowidOffset/aRowidOffset:
+**     These are used if the FTS5_SEGITER_REVERSE flag is set.
+**
+**     For each rowid on the page corresponding to the current term, the
+**     corresponding aRowidOffset[] entry is set to the byte offset of the
+**     start of the "position-list-size" field within the page.
+**
+** iTermIdx:
+**     Index of current term on iTermLeafPgno.
+*/
+struct Fts5SegIter {
+  Fts5StructureSegment *pSeg;     /* Segment to iterate through */
+  int flags;                      /* Mask of configuration flags */
+  int iLeafPgno;                  /* Current leaf page number */
+  Fts5Data *pLeaf;                /* Current leaf data */
+  Fts5Data *pNextLeaf;            /* Leaf page (iLeafPgno+1) */
+  int iLeafOffset;                /* Byte offset within current leaf */
+
+  /* The page and offset from which the current term was read. The offset 
+  ** is the offset of the first rowid in the current doclist.  */
+  int iTermLeafPgno;
+  int iTermLeafOffset;
+
+  int iPgidxOff;                  /* Next offset in pgidx */
+  int iEndofDoclist;
+
+  /* The following are only used if the FTS5_SEGITER_REVERSE flag is set. */
+  int iRowidOffset;               /* Current entry in aRowidOffset[] */
+  int nRowidOffset;               /* Allocated size of aRowidOffset[] array */
+  int *aRowidOffset;              /* Array of offset to rowid fields */
+
+  Fts5DlidxIter *pDlidx;          /* If there is a doclist-index */
+
+  /* Variables populated based on current entry. */
+  Fts5Buffer term;                /* Current term */
+  i64 iRowid;                     /* Current rowid */
+  int nPos;                       /* Number of bytes in current position list */
+  int bDel;                       /* True if the delete flag is set */
+};
+
+/*
+** Argument is a pointer to an Fts5Data structure that contains a 
+** leaf page.
+*/
+#define ASSERT_SZLEAF_OK(x) assert( \
+    (x)->szLeaf==(x)->nn || (x)->szLeaf==fts5GetU16(&(x)->p[2]) \
+)
+
+#define FTS5_SEGITER_ONETERM 0x01
+#define FTS5_SEGITER_REVERSE 0x02
+
+
+/* 
+** Argument is a pointer to an Fts5Data structure that contains a leaf
+** page. This macro evaluates to true if the leaf contains no terms, or
+** false if it contains at least one term.
+*/
+#define fts5LeafIsTermless(x) ((x)->szLeaf >= (x)->nn)
+
+#define fts5LeafTermOff(x, i) (fts5GetU16(&(x)->p[(x)->szLeaf + (i)*2]))
+
+#define fts5LeafFirstRowidOff(x) (fts5GetU16((x)->p))
+
+/*
+** poslist:
+**   Used by sqlite3Fts5IterPoslist() when the poslist needs to be buffered.
+**   There is no way to tell if this is populated or not.
+*/
+struct Fts5IndexIter {
+  Fts5Index *pIndex;              /* Index that owns this iterator */
+  Fts5Structure *pStruct;         /* Database structure for this iterator */
+  Fts5Buffer poslist;             /* Buffer containing current poslist */
+
+  int nSeg;                       /* Size of aSeg[] array */
+  int bRev;                       /* True to iterate in reverse order */
+  u8 bSkipEmpty;                  /* True to skip deleted entries */
+  u8 bEof;                        /* True at EOF */
+  u8 bFiltered;                   /* True if column-filter already applied */
+
+  i64 iSwitchRowid;               /* Firstest rowid of other than aFirst[1] */
+  Fts5CResult *aFirst;            /* Current merge state (see above) */
+  Fts5SegIter aSeg[1];            /* Array of segment iterators */
+};
+
+
+/*
+** An instance of the following type is used to iterate through the contents
+** of a doclist-index record.
+**
+** pData:
+**   Record containing the doclist-index data.
+**
+** bEof:
+**   Set to true once iterator has reached EOF.
+**
+** iOff:
+**   Set to the current offset within record pData.
+*/
+struct Fts5DlidxLvl {
+  Fts5Data *pData;              /* Data for current page of this level */
+  int iOff;                     /* Current offset into pData */
+  int bEof;                     /* At EOF already */
+  int iFirstOff;                /* Used by reverse iterators */
+
+  /* Output variables */
+  int iLeafPgno;                /* Page number of current leaf page */
+  i64 iRowid;                   /* First rowid on leaf iLeafPgno */
+};
+struct Fts5DlidxIter {
+  int nLvl;
+  int iSegid;
+  Fts5DlidxLvl aLvl[1];
+};
+
+static void fts5PutU16(u8 *aOut, u16 iVal){
+  aOut[0] = (iVal>>8);
+  aOut[1] = (iVal&0xFF);
+}
+
+static u16 fts5GetU16(const u8 *aIn){
+  return ((u16)aIn[0] << 8) + aIn[1];
+} 
+
+/*
+** Allocate and return a buffer at least nByte bytes in size.
+**
+** If an OOM error is encountered, return NULL and set the error code in
+** the Fts5Index handle passed as the first argument.
+*/
+static void *fts5IdxMalloc(Fts5Index *p, int nByte){
+  return sqlite3Fts5MallocZero(&p->rc, nByte);
+}
+
+/*
+** Compare the contents of the pLeft buffer with the pRight/nRight blob.
+**
+** Return -ve if pLeft is smaller than pRight, 0 if they are equal or
+** +ve if pRight is smaller than pLeft. In other words:
+**
+**     res = *pLeft - *pRight
+*/
+#ifdef SQLITE_DEBUG
+static int fts5BufferCompareBlob(
+  Fts5Buffer *pLeft,              /* Left hand side of comparison */
+  const u8 *pRight, int nRight    /* Right hand side of comparison */
+){
+  int nCmp = MIN(pLeft->n, nRight);
+  int res = memcmp(pLeft->p, pRight, nCmp);
+  return (res==0 ? (pLeft->n - nRight) : res);
+}
+#endif
+
+/*
+** Compare the contents of the two buffers using memcmp(). If one buffer
+** is a prefix of the other, it is considered the lesser.
+**
+** Return -ve if pLeft is smaller than pRight, 0 if they are equal or
+** +ve if pRight is smaller than pLeft. In other words:
+**
+**     res = *pLeft - *pRight
+*/
+static int fts5BufferCompare(Fts5Buffer *pLeft, Fts5Buffer *pRight){
+  int nCmp = MIN(pLeft->n, pRight->n);
+  int res = memcmp(pLeft->p, pRight->p, nCmp);
+  return (res==0 ? (pLeft->n - pRight->n) : res);
+}
+
+#ifdef SQLITE_DEBUG
+static int fts5BlobCompare(
+  const u8 *pLeft, int nLeft, 
+  const u8 *pRight, int nRight
+){
+  int nCmp = MIN(nLeft, nRight);
+  int res = memcmp(pLeft, pRight, nCmp);
+  return (res==0 ? (nLeft - nRight) : res);
+}
+#endif
+
+static int fts5LeafFirstTermOff(Fts5Data *pLeaf){
+  int ret;
+  fts5GetVarint32(&pLeaf->p[pLeaf->szLeaf], ret);
+  return ret;
+}
+
+/*
+** Close the read-only blob handle, if it is open.
+*/
+static void fts5CloseReader(Fts5Index *p){
+  if( p->pReader ){
+    sqlite3_blob *pReader = p->pReader;
+    p->pReader = 0;
+    sqlite3_blob_close(pReader);
+  }
+}
+
+
+/*
+** Retrieve a record from the %_data table.
+**
+** If an error occurs, NULL is returned and an error left in the 
+** Fts5Index object.
+*/
+static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
+  Fts5Data *pRet = 0;
+  if( p->rc==SQLITE_OK ){
+    int rc = SQLITE_OK;
+
+    if( p->pReader ){
+      /* This call may return SQLITE_ABORT if there has been a savepoint
+      ** rollback since it was last used. In this case a new blob handle
+      ** is required.  */
+      sqlite3_blob *pBlob = p->pReader;
+      p->pReader = 0;
+      rc = sqlite3_blob_reopen(pBlob, iRowid);
+      assert( p->pReader==0 );
+      p->pReader = pBlob;
+      if( rc!=SQLITE_OK ){
+        fts5CloseReader(p);
+      }
+      if( rc==SQLITE_ABORT ) rc = SQLITE_OK;
+    }
+
+    /* If the blob handle is not open at this point, open it and seek 
+    ** to the requested entry.  */
+    if( p->pReader==0 && rc==SQLITE_OK ){
+      Fts5Config *pConfig = p->pConfig;
+      rc = sqlite3_blob_open(pConfig->db, 
+          pConfig->zDb, p->zDataTbl, "block", iRowid, 0, &p->pReader
+      );
+    }
+
+    /* If either of the sqlite3_blob_open() or sqlite3_blob_reopen() calls
+    ** above returned SQLITE_ERROR, return SQLITE_CORRUPT_VTAB instead.
+    ** All the reasons those functions might return SQLITE_ERROR - missing
+    ** table, missing row, non-blob/text in block column - indicate 
+    ** backing store corruption.  */
+    if( rc==SQLITE_ERROR ) rc = FTS5_CORRUPT;
+
+    if( rc==SQLITE_OK ){
+      u8 *aOut = 0;               /* Read blob data into this buffer */
+      int nByte = sqlite3_blob_bytes(p->pReader);
+      int nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING;
+      pRet = (Fts5Data*)sqlite3_malloc(nAlloc);
+      if( pRet ){
+        pRet->nn = nByte;
+        aOut = pRet->p = (u8*)&pRet[1];
+      }else{
+        rc = SQLITE_NOMEM;
+      }
+
+      if( rc==SQLITE_OK ){
+        rc = sqlite3_blob_read(p->pReader, aOut, nByte, 0);
+      }
+      if( rc!=SQLITE_OK ){
+        sqlite3_free(pRet);
+        pRet = 0;
+      }else{
+        /* TODO1: Fix this */
+        pRet->szLeaf = fts5GetU16(&pRet->p[2]);
+      }
+    }
+    p->rc = rc;
+    p->nRead++;
+  }
+
+  assert( (pRet==0)==(p->rc!=SQLITE_OK) );
+  return pRet;
+}
+
+/*
+** Release a reference to data record returned by an earlier call to
+** fts5DataRead().
+*/
+static void fts5DataRelease(Fts5Data *pData){
+  sqlite3_free(pData);
+}
+
+static int fts5IndexPrepareStmt(
+  Fts5Index *p,
+  sqlite3_stmt **ppStmt,
+  char *zSql
+){
+  if( p->rc==SQLITE_OK ){
+    if( zSql ){
+      p->rc = sqlite3_prepare_v2(p->pConfig->db, zSql, -1, ppStmt, 0);
+    }else{
+      p->rc = SQLITE_NOMEM;
+    }
+  }
+  sqlite3_free(zSql);
+  return p->rc;
+}
+
+
+/*
+** INSERT OR REPLACE a record into the %_data table.
+*/
+static void fts5DataWrite(Fts5Index *p, i64 iRowid, const u8 *pData, int nData){
+  if( p->rc!=SQLITE_OK ) return;
+
+  if( p->pWriter==0 ){
+    Fts5Config *pConfig = p->pConfig;
+    fts5IndexPrepareStmt(p, &p->pWriter, sqlite3_mprintf(
+          "REPLACE INTO '%q'.'%q_data'(id, block) VALUES(?,?)", 
+          pConfig->zDb, pConfig->zName
+    ));
+    if( p->rc ) return;
+  }
+
+  sqlite3_bind_int64(p->pWriter, 1, iRowid);
+  sqlite3_bind_blob(p->pWriter, 2, pData, nData, SQLITE_STATIC);
+  sqlite3_step(p->pWriter);
+  p->rc = sqlite3_reset(p->pWriter);
+}
+
+/*
+** Execute the following SQL:
+**
+**     DELETE FROM %_data WHERE id BETWEEN $iFirst AND $iLast
+*/
+static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){
+  if( p->rc!=SQLITE_OK ) return;
+
+  if( p->pDeleter==0 ){
+    int rc;
+    Fts5Config *pConfig = p->pConfig;
+    char *zSql = sqlite3_mprintf(
+        "DELETE FROM '%q'.'%q_data' WHERE id>=? AND id<=?", 
+          pConfig->zDb, pConfig->zName
+    );
+    if( zSql==0 ){
+      rc = SQLITE_NOMEM;
+    }else{
+      rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &p->pDeleter, 0);
+      sqlite3_free(zSql);
+    }
+    if( rc!=SQLITE_OK ){
+      p->rc = rc;
+      return;
+    }
+  }
+
+  sqlite3_bind_int64(p->pDeleter, 1, iFirst);
+  sqlite3_bind_int64(p->pDeleter, 2, iLast);
+  sqlite3_step(p->pDeleter);
+  p->rc = sqlite3_reset(p->pDeleter);
+}
+
+/*
+** Remove all records associated with segment iSegid.
+*/
+static void fts5DataRemoveSegment(Fts5Index *p, int iSegid){
+  i64 iFirst = FTS5_SEGMENT_ROWID(iSegid, 0);
+  i64 iLast = FTS5_SEGMENT_ROWID(iSegid+1, 0)-1;
+  fts5DataDelete(p, iFirst, iLast);
+  if( p->pIdxDeleter==0 ){
+    Fts5Config *pConfig = p->pConfig;
+    fts5IndexPrepareStmt(p, &p->pIdxDeleter, sqlite3_mprintf(
+          "DELETE FROM '%q'.'%q_idx' WHERE segid=?",
+          pConfig->zDb, pConfig->zName
+    ));
+  }
+  if( p->rc==SQLITE_OK ){
+    sqlite3_bind_int(p->pIdxDeleter, 1, iSegid);
+    sqlite3_step(p->pIdxDeleter);
+    p->rc = sqlite3_reset(p->pIdxDeleter);
+  }
+}
+
+/*
+** Release a reference to an Fts5Structure object returned by an earlier 
+** call to fts5StructureRead() or fts5StructureDecode().
+*/
+static void fts5StructureRelease(Fts5Structure *pStruct){
+  if( pStruct && 0>=(--pStruct->nRef) ){
+    int i;
+    assert( pStruct->nRef==0 );
+    for(i=0; i<pStruct->nLevel; i++){
+      sqlite3_free(pStruct->aLevel[i].aSeg);
+    }
+    sqlite3_free(pStruct);
+  }
+}
+
+static void fts5StructureRef(Fts5Structure *pStruct){
+  pStruct->nRef++;
+}
+
+/*
+** Deserialize and return the structure record currently stored in serialized
+** form within buffer pData/nData.
+**
+** The Fts5Structure.aLevel[] and each Fts5StructureLevel.aSeg[] array
+** are over-allocated by one slot. This allows the structure contents
+** to be more easily edited.
+**
+** If an error occurs, *ppOut is set to NULL and an SQLite error code
+** returned. Otherwise, *ppOut is set to point to the new object and
+** SQLITE_OK returned.
+*/
+static int fts5StructureDecode(
+  const u8 *pData,                /* Buffer containing serialized structure */
+  int nData,                      /* Size of buffer pData in bytes */
+  int *piCookie,                  /* Configuration cookie value */
+  Fts5Structure **ppOut           /* OUT: Deserialized object */
+){
+  int rc = SQLITE_OK;
+  int i = 0;
+  int iLvl;
+  int nLevel = 0;
+  int nSegment = 0;
+  int nByte;                      /* Bytes of space to allocate at pRet */
+  Fts5Structure *pRet = 0;        /* Structure object to return */
+
+  /* Grab the cookie value */
+  if( piCookie ) *piCookie = sqlite3Fts5Get32(pData);
+  i = 4;
+
+  /* Read the total number of levels and segments from the start of the
+  ** structure record.  */
+  i += fts5GetVarint32(&pData[i], nLevel);
+  i += fts5GetVarint32(&pData[i], nSegment);
+  nByte = (
+      sizeof(Fts5Structure) +                    /* Main structure */
+      sizeof(Fts5StructureLevel) * (nLevel-1)    /* aLevel[] array */
+  );
+  pRet = (Fts5Structure*)sqlite3Fts5MallocZero(&rc, nByte);
+
+  if( pRet ){
+    pRet->nRef = 1;
+    pRet->nLevel = nLevel;
+    pRet->nSegment = nSegment;
+    i += sqlite3Fts5GetVarint(&pData[i], &pRet->nWriteCounter);
+
+    for(iLvl=0; rc==SQLITE_OK && iLvl<nLevel; iLvl++){
+      Fts5StructureLevel *pLvl = &pRet->aLevel[iLvl];
+      int nTotal;
+      int iSeg;
+
+      i += fts5GetVarint32(&pData[i], pLvl->nMerge);
+      i += fts5GetVarint32(&pData[i], nTotal);
+      assert( nTotal>=pLvl->nMerge );
+      pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc, 
+          nTotal * sizeof(Fts5StructureSegment)
+      );
+
+      if( rc==SQLITE_OK ){
+        pLvl->nSeg = nTotal;
+        for(iSeg=0; iSeg<nTotal; iSeg++){
+          i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].iSegid);
+          i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoFirst);
+          i += fts5GetVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoLast);
+        }
+      }else{
+        fts5StructureRelease(pRet);
+        pRet = 0;
+      }
+    }
+  }
+
+  *ppOut = pRet;
+  return rc;
+}
+
+/*
+**
+*/
+static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){
+  if( *pRc==SQLITE_OK ){
+    Fts5Structure *pStruct = *ppStruct;
+    int nLevel = pStruct->nLevel;
+    int nByte = (
+        sizeof(Fts5Structure) +                  /* Main structure */
+        sizeof(Fts5StructureLevel) * (nLevel+1)  /* aLevel[] array */
+    );
+
+    pStruct = sqlite3_realloc(pStruct, nByte);
+    if( pStruct ){
+      memset(&pStruct->aLevel[nLevel], 0, sizeof(Fts5StructureLevel));
+      pStruct->nLevel++;
+      *ppStruct = pStruct;
+    }else{
+      *pRc = SQLITE_NOMEM;
+    }
+  }
+}
+
+/*
+** Extend level iLvl so that there is room for at least nExtra more
+** segments.
+*/
+static void fts5StructureExtendLevel(
+  int *pRc, 
+  Fts5Structure *pStruct, 
+  int iLvl, 
+  int nExtra, 
+  int bInsert
+){
+  if( *pRc==SQLITE_OK ){
+    Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
+    Fts5StructureSegment *aNew;
+    int nByte;
+
+    nByte = (pLvl->nSeg + nExtra) * sizeof(Fts5StructureSegment);
+    aNew = sqlite3_realloc(pLvl->aSeg, nByte);
+    if( aNew ){
+      if( bInsert==0 ){
+        memset(&aNew[pLvl->nSeg], 0, sizeof(Fts5StructureSegment) * nExtra);
+      }else{
+        int nMove = pLvl->nSeg * sizeof(Fts5StructureSegment);
+        memmove(&aNew[nExtra], aNew, nMove);
+        memset(aNew, 0, sizeof(Fts5StructureSegment) * nExtra);
+      }
+      pLvl->aSeg = aNew;
+    }else{
+      *pRc = SQLITE_NOMEM;
+    }
+  }
+}
+
+/*
+** Read, deserialize and return the structure record.
+**
+** The Fts5Structure.aLevel[] and each Fts5StructureLevel.aSeg[] array
+** are over-allocated as described for function fts5StructureDecode() 
+** above.
+**
+** If an error occurs, NULL is returned and an error code left in the
+** Fts5Index handle. If an error has already occurred when this function
+** is called, it is a no-op.
+*/
+static Fts5Structure *fts5StructureRead(Fts5Index *p){
+  Fts5Config *pConfig = p->pConfig;
+  Fts5Structure *pRet = 0;        /* Object to return */
+  int iCookie;                    /* Configuration cookie */
+  Fts5Data *pData;
+
+  pData = fts5DataRead(p, FTS5_STRUCTURE_ROWID);
+  if( p->rc ) return 0;
+  /* TODO: Do we need this if the leaf-index is appended? Probably... */
+  memset(&pData->p[pData->nn], 0, FTS5_DATA_PADDING);
+  p->rc = fts5StructureDecode(pData->p, pData->nn, &iCookie, &pRet);
+  if( p->rc==SQLITE_OK && pConfig->iCookie!=iCookie ){
+    p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie);
+  }
+
+  fts5DataRelease(pData);
+  if( p->rc!=SQLITE_OK ){
+    fts5StructureRelease(pRet);
+    pRet = 0;
+  }
+  return pRet;
+}
+
+/*
+** Return the total number of segments in index structure pStruct. This
+** function is only ever used as part of assert() conditions.
+*/
+#ifdef SQLITE_DEBUG
+static int fts5StructureCountSegments(Fts5Structure *pStruct){
+  int nSegment = 0;               /* Total number of segments */
+  if( pStruct ){
+    int iLvl;                     /* Used to iterate through levels */
+    for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
+      nSegment += pStruct->aLevel[iLvl].nSeg;
+    }
+  }
+
+  return nSegment;
+}
+#endif
+
+/*
+** Serialize and store the "structure" record.
+**
+** If an error occurs, leave an error code in the Fts5Index object. If an
+** error has already occurred, this function is a no-op.
+*/
+static void fts5StructureWrite(Fts5Index *p, Fts5Structure *pStruct){
+  if( p->rc==SQLITE_OK ){
+    Fts5Buffer buf;               /* Buffer to serialize record into */
+    int iLvl;                     /* Used to iterate through levels */
+    int iCookie;                  /* Cookie value to store */
+
+    assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) );
+    memset(&buf, 0, sizeof(Fts5Buffer));
+
+    /* Append the current configuration cookie */
+    iCookie = p->pConfig->iCookie;
+    if( iCookie<0 ) iCookie = 0;
+    fts5BufferAppend32(&p->rc, &buf, iCookie);
+
+    fts5BufferAppendVarint(&p->rc, &buf, pStruct->nLevel);
+    fts5BufferAppendVarint(&p->rc, &buf, pStruct->nSegment);
+    fts5BufferAppendVarint(&p->rc, &buf, (i64)pStruct->nWriteCounter);
+
+    for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
+      int iSeg;                     /* Used to iterate through segments */
+      Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
+      fts5BufferAppendVarint(&p->rc, &buf, pLvl->nMerge);
+      fts5BufferAppendVarint(&p->rc, &buf, pLvl->nSeg);
+      assert( pLvl->nMerge<=pLvl->nSeg );
+
+      for(iSeg=0; iSeg<pLvl->nSeg; iSeg++){
+        fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].iSegid);
+        fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].pgnoFirst);
+        fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].pgnoLast);
+      }
+    }
+
+    fts5DataWrite(p, FTS5_STRUCTURE_ROWID, buf.p, buf.n);
+    fts5BufferFree(&buf);
+  }
+}
+
+#if 0
+static void fts5DebugStructure(int*,Fts5Buffer*,Fts5Structure*);
+static void fts5PrintStructure(const char *zCaption, Fts5Structure *pStruct){
+  int rc = SQLITE_OK;
+  Fts5Buffer buf;
+  memset(&buf, 0, sizeof(buf));
+  fts5DebugStructure(&rc, &buf, pStruct);
+  fprintf(stdout, "%s: %s\n", zCaption, buf.p);
+  fflush(stdout);
+  fts5BufferFree(&buf);
+}
+#else
+# define fts5PrintStructure(x,y)
+#endif
+
+static int fts5SegmentSize(Fts5StructureSegment *pSeg){
+  return 1 + pSeg->pgnoLast - pSeg->pgnoFirst;
+}
+
+/*
+** Return a copy of index structure pStruct. Except, promote as many 
+** segments as possible to level iPromote. If an OOM occurs, NULL is 
+** returned.
+*/
+static void fts5StructurePromoteTo(
+  Fts5Index *p,
+  int iPromote,
+  int szPromote,
+  Fts5Structure *pStruct
+){
+  int il, is;
+  Fts5StructureLevel *pOut = &pStruct->aLevel[iPromote];
+
+  if( pOut->nMerge==0 ){
+    for(il=iPromote+1; il<pStruct->nLevel; il++){
+      Fts5StructureLevel *pLvl = &pStruct->aLevel[il];
+      if( pLvl->nMerge ) return;
+      for(is=pLvl->nSeg-1; is>=0; is--){
+        int sz = fts5SegmentSize(&pLvl->aSeg[is]);
+        if( sz>szPromote ) return;
+        fts5StructureExtendLevel(&p->rc, pStruct, iPromote, 1, 1);
+        if( p->rc ) return;
+        memcpy(pOut->aSeg, &pLvl->aSeg[is], sizeof(Fts5StructureSegment));
+        pOut->nSeg++;
+        pLvl->nSeg--;
+      }
+    }
+  }
+}
+
+/*
+** A new segment has just been written to level iLvl of index structure
+** pStruct. This function determines if any segments should be promoted
+** as a result. Segments are promoted in two scenarios:
+**
+**   a) If the segment just written is smaller than one or more segments
+**      within the previous populated level, it is promoted to the previous
+**      populated level.
+**
+**   b) If the segment just written is larger than the newest segment on
+**      the next populated level, then that segment, and any other adjacent
+**      segments that are also smaller than the one just written, are 
+**      promoted. 
+**
+** If one or more segments are promoted, the structure object is updated
+** to reflect this.
+*/
+static void fts5StructurePromote(
+  Fts5Index *p,                   /* FTS5 backend object */
+  int iLvl,                       /* Index level just updated */
+  Fts5Structure *pStruct          /* Index structure */
+){
+  if( p->rc==SQLITE_OK ){
+    int iTst;
+    int iPromote = -1;
+    int szPromote = 0;            /* Promote anything this size or smaller */
+    Fts5StructureSegment *pSeg;   /* Segment just written */
+    int szSeg;                    /* Size of segment just written */
+    int nSeg = pStruct->aLevel[iLvl].nSeg;
+
+    if( nSeg==0 ) return;
+    pSeg = &pStruct->aLevel[iLvl].aSeg[pStruct->aLevel[iLvl].nSeg-1];
+    szSeg = (1 + pSeg->pgnoLast - pSeg->pgnoFirst);
+
+    /* Check for condition (a) */
+    for(iTst=iLvl-1; iTst>=0 && pStruct->aLevel[iTst].nSeg==0; iTst--);
+    if( iTst>=0 ){
+      int i;
+      int szMax = 0;
+      Fts5StructureLevel *pTst = &pStruct->aLevel[iTst];
+      assert( pTst->nMerge==0 );
+      for(i=0; i<pTst->nSeg; i++){
+        int sz = pTst->aSeg[i].pgnoLast - pTst->aSeg[i].pgnoFirst + 1;
+        if( sz>szMax ) szMax = sz;
+      }
+      if( szMax>=szSeg ){
+        /* Condition (a) is true. Promote the newest segment on level 
+        ** iLvl to level iTst.  */
+        iPromote = iTst;
+        szPromote = szMax;
+      }
+    }
+
+    /* If condition (a) is not met, assume (b) is true. StructurePromoteTo()
+    ** is a no-op if it is not.  */
+    if( iPromote<0 ){
+      iPromote = iLvl;
+      szPromote = szSeg;
+    }
+    fts5StructurePromoteTo(p, iPromote, szPromote, pStruct);
+  }
+}
+
+
+/*
+** Advance the iterator passed as the only argument. If the end of the 
+** doclist-index page is reached, return non-zero.
+*/
+static int fts5DlidxLvlNext(Fts5DlidxLvl *pLvl){
+  Fts5Data *pData = pLvl->pData;
+
+  if( pLvl->iOff==0 ){
+    assert( pLvl->bEof==0 );
+    pLvl->iOff = 1;
+    pLvl->iOff += fts5GetVarint32(&pData->p[1], pLvl->iLeafPgno);
+    pLvl->iOff += fts5GetVarint(&pData->p[pLvl->iOff], (u64*)&pLvl->iRowid);
+    pLvl->iFirstOff = pLvl->iOff;
+  }else{
+    int iOff;
+    for(iOff=pLvl->iOff; iOff<pData->nn; iOff++){
+      if( pData->p[iOff] ) break; 
+    }
+
+    if( iOff<pData->nn ){
+      i64 iVal;
+      pLvl->iLeafPgno += (iOff - pLvl->iOff) + 1;
+      iOff += fts5GetVarint(&pData->p[iOff], (u64*)&iVal);
+      pLvl->iRowid += iVal;
+      pLvl->iOff = iOff;
+    }else{
+      pLvl->bEof = 1;
+    }
+  }
+
+  return pLvl->bEof;
+}
+
+/*
+** Advance the iterator passed as the only argument.
+*/
+static int fts5DlidxIterNextR(Fts5Index *p, Fts5DlidxIter *pIter, int iLvl){
+  Fts5DlidxLvl *pLvl = &pIter->aLvl[iLvl];
+
+  assert( iLvl<pIter->nLvl );
+  if( fts5DlidxLvlNext(pLvl) ){
+    if( (iLvl+1) < pIter->nLvl ){
+      fts5DlidxIterNextR(p, pIter, iLvl+1);
+      if( pLvl[1].bEof==0 ){
+        fts5DataRelease(pLvl->pData);
+        memset(pLvl, 0, sizeof(Fts5DlidxLvl));
+        pLvl->pData = fts5DataRead(p, 
+            FTS5_DLIDX_ROWID(pIter->iSegid, iLvl, pLvl[1].iLeafPgno)
+        );
+        if( pLvl->pData ) fts5DlidxLvlNext(pLvl);
+      }
+    }
+  }
+
+  return pIter->aLvl[0].bEof;
+}
+static int fts5DlidxIterNext(Fts5Index *p, Fts5DlidxIter *pIter){
+  return fts5DlidxIterNextR(p, pIter, 0);
+}
+
+/*
+** The iterator passed as the first argument has the following fields set
+** as follows. This function sets up the rest of the iterator so that it
+** points to the first rowid in the doclist-index.
+**
+**   pData:
+**     pointer to doclist-index record, 
+**
+** When this function is called pIter->iLeafPgno is the page number the
+** doclist is associated with (the one featuring the term).
+*/
+static int fts5DlidxIterFirst(Fts5DlidxIter *pIter){
+  int i;
+  for(i=0; i<pIter->nLvl; i++){
+    fts5DlidxLvlNext(&pIter->aLvl[i]);
+  }
+  return pIter->aLvl[0].bEof;
+}
+
+
+static int fts5DlidxIterEof(Fts5Index *p, Fts5DlidxIter *pIter){
+  return p->rc!=SQLITE_OK || pIter->aLvl[0].bEof;
+}
+
+static void fts5DlidxIterLast(Fts5Index *p, Fts5DlidxIter *pIter){
+  int i;
+
+  /* Advance each level to the last entry on the last page */
+  for(i=pIter->nLvl-1; p->rc==SQLITE_OK && i>=0; i--){
+    Fts5DlidxLvl *pLvl = &pIter->aLvl[i];
+    while( fts5DlidxLvlNext(pLvl)==0 );
+    pLvl->bEof = 0;
+
+    if( i>0 ){
+      Fts5DlidxLvl *pChild = &pLvl[-1];
+      fts5DataRelease(pChild->pData);
+      memset(pChild, 0, sizeof(Fts5DlidxLvl));
+      pChild->pData = fts5DataRead(p, 
+          FTS5_DLIDX_ROWID(pIter->iSegid, i-1, pLvl->iLeafPgno)
+      );
+    }
+  }
+}
+
+/*
+** Move the iterator passed as the only argument to the previous entry.
+*/
+static int fts5DlidxLvlPrev(Fts5DlidxLvl *pLvl){
+  int iOff = pLvl->iOff;
+
+  assert( pLvl->bEof==0 );
+  if( iOff<=pLvl->iFirstOff ){
+    pLvl->bEof = 1;
+  }else{
+    u8 *a = pLvl->pData->p;
+    i64 iVal;
+    int iLimit;
+    int ii;
+    int nZero = 0;
+
+    /* Currently iOff points to the first byte of a varint. This block 
+    ** decrements iOff until it points to the first byte of the previous 
+    ** varint. Taking care not to read any memory locations that occur
+    ** before the buffer in memory.  */
+    iLimit = (iOff>9 ? iOff-9 : 0);
+    for(iOff--; iOff>iLimit; iOff--){
+      if( (a[iOff-1] & 0x80)==0 ) break;
+    }
+
+    fts5GetVarint(&a[iOff], (u64*)&iVal);
+    pLvl->iRowid -= iVal;
+    pLvl->iLeafPgno--;
+
+    /* Skip backwards past any 0x00 varints. */
+    for(ii=iOff-1; ii>=pLvl->iFirstOff && a[ii]==0x00; ii--){
+      nZero++;
+    }
+    if( ii>=pLvl->iFirstOff && (a[ii] & 0x80) ){
+      /* The byte immediately before the last 0x00 byte has the 0x80 bit
+      ** set. So the last 0x00 is only a varint 0 if there are 8 more 0x80
+      ** bytes before a[ii]. */
+      int bZero = 0;              /* True if last 0x00 counts */
+      if( (ii-8)>=pLvl->iFirstOff ){
+        int j;
+        for(j=1; j<=8 && (a[ii-j] & 0x80); j++);
+        bZero = (j>8);
+      }
+      if( bZero==0 ) nZero--;
+    }
+    pLvl->iLeafPgno -= nZero;
+    pLvl->iOff = iOff - nZero;
+  }
+
+  return pLvl->bEof;
+}
+
+static int fts5DlidxIterPrevR(Fts5Index *p, Fts5DlidxIter *pIter, int iLvl){
+  Fts5DlidxLvl *pLvl = &pIter->aLvl[iLvl];
+
+  assert( iLvl<pIter->nLvl );
+  if( fts5DlidxLvlPrev(pLvl) ){
+    if( (iLvl+1) < pIter->nLvl ){
+      fts5DlidxIterPrevR(p, pIter, iLvl+1);
+      if( pLvl[1].bEof==0 ){
+        fts5DataRelease(pLvl->pData);
+        memset(pLvl, 0, sizeof(Fts5DlidxLvl));
+        pLvl->pData = fts5DataRead(p, 
+            FTS5_DLIDX_ROWID(pIter->iSegid, iLvl, pLvl[1].iLeafPgno)
+        );
+        if( pLvl->pData ){
+          while( fts5DlidxLvlNext(pLvl)==0 );
+          pLvl->bEof = 0;
+        }
+      }
+    }
+  }
+
+  return pIter->aLvl[0].bEof;
+}
+static int fts5DlidxIterPrev(Fts5Index *p, Fts5DlidxIter *pIter){
+  return fts5DlidxIterPrevR(p, pIter, 0);
+}
+
+/*
+** Free a doclist-index iterator object allocated by fts5DlidxIterInit().
+*/
+static void fts5DlidxIterFree(Fts5DlidxIter *pIter){
+  if( pIter ){
+    int i;
+    for(i=0; i<pIter->nLvl; i++){
+      fts5DataRelease(pIter->aLvl[i].pData);
+    }
+    sqlite3_free(pIter);
+  }
+}
+
+static Fts5DlidxIter *fts5DlidxIterInit(
+  Fts5Index *p,                   /* Fts5 Backend to iterate within */
+  int bRev,                       /* True for ORDER BY ASC */
+  int iSegid,                     /* Segment id */
+  int iLeafPg                     /* Leaf page number to load dlidx for */
+){
+  Fts5DlidxIter *pIter = 0;
+  int i;
+  int bDone = 0;
+
+  for(i=0; p->rc==SQLITE_OK && bDone==0; i++){
+    int nByte = sizeof(Fts5DlidxIter) + i * sizeof(Fts5DlidxLvl);
+    Fts5DlidxIter *pNew;
+
+    pNew = (Fts5DlidxIter*)sqlite3_realloc(pIter, nByte);
+    if( pNew==0 ){
+      p->rc = SQLITE_NOMEM;
+    }else{
+      i64 iRowid = FTS5_DLIDX_ROWID(iSegid, i, iLeafPg);
+      Fts5DlidxLvl *pLvl = &pNew->aLvl[i];
+      pIter = pNew;
+      memset(pLvl, 0, sizeof(Fts5DlidxLvl));
+      pLvl->pData = fts5DataRead(p, iRowid);
+      if( pLvl->pData && (pLvl->pData->p[0] & 0x0001)==0 ){
+        bDone = 1;
+      }
+      pIter->nLvl = i+1;
+    }
+  }
+
+  if( p->rc==SQLITE_OK ){
+    pIter->iSegid = iSegid;
+    if( bRev==0 ){
+      fts5DlidxIterFirst(pIter);
+    }else{
+      fts5DlidxIterLast(p, pIter);
+    }
+  }
+
+  if( p->rc!=SQLITE_OK ){
+    fts5DlidxIterFree(pIter);
+    pIter = 0;
+  }
+
+  return pIter;
+}
+
+static i64 fts5DlidxIterRowid(Fts5DlidxIter *pIter){
+  return pIter->aLvl[0].iRowid;
+}
+static int fts5DlidxIterPgno(Fts5DlidxIter *pIter){
+  return pIter->aLvl[0].iLeafPgno;
+}
+
+/*
+** Load the next leaf page into the segment iterator.
+*/
+static void fts5SegIterNextPage(
+  Fts5Index *p,                   /* FTS5 backend object */
+  Fts5SegIter *pIter              /* Iterator to advance to next page */
+){
+  Fts5Data *pLeaf;
+  Fts5StructureSegment *pSeg = pIter->pSeg;
+  fts5DataRelease(pIter->pLeaf);
+  pIter->iLeafPgno++;
+  if( pIter->pNextLeaf ){
+    pIter->pLeaf = pIter->pNextLeaf;
+    pIter->pNextLeaf = 0;
+  }else if( pIter->iLeafPgno<=pSeg->pgnoLast ){
+    pIter->pLeaf = fts5DataRead(p, 
+        FTS5_SEGMENT_ROWID(pSeg->iSegid, pIter->iLeafPgno)
+    );
+  }else{
+    pIter->pLeaf = 0;
+  }
+  pLeaf = pIter->pLeaf;
+
+  if( pLeaf ){
+    pIter->iPgidxOff = pLeaf->szLeaf;
+    if( fts5LeafIsTermless(pLeaf) ){
+      pIter->iEndofDoclist = pLeaf->nn+1;
+    }else{
+      pIter->iPgidxOff += fts5GetVarint32(&pLeaf->p[pIter->iPgidxOff],
+          pIter->iEndofDoclist
+      );
+    }
+  }
+}
+
+/*
+** Argument p points to a buffer containing a varint to be interpreted as a
+** position list size field. Read the varint and return the number of bytes
+** read. Before returning, set *pnSz to the number of bytes in the position
+** list, and *pbDel to true if the delete flag is set, or false otherwise.
+*/
+static int fts5GetPoslistSize(const u8 *p, int *pnSz, int *pbDel){
+  int nSz;
+  int n = 0;
+  fts5FastGetVarint32(p, n, nSz);
+  assert_nc( nSz>=0 );
+  *pnSz = nSz/2;
+  *pbDel = nSz & 0x0001;
+  return n;
+}
+
+/*
+** Fts5SegIter.iLeafOffset currently points to the first byte of a
+** position-list size field. Read the value of the field and store it
+** in the following variables:
+**
+**   Fts5SegIter.nPos
+**   Fts5SegIter.bDel
+**
+** Leave Fts5SegIter.iLeafOffset pointing to the first byte of the 
+** position list content (if any).
+*/
+static void fts5SegIterLoadNPos(Fts5Index *p, Fts5SegIter *pIter){
+  if( p->rc==SQLITE_OK ){
+    int iOff = pIter->iLeafOffset;  /* Offset to read at */
+    int nSz;
+    ASSERT_SZLEAF_OK(pIter->pLeaf);
+    fts5FastGetVarint32(pIter->pLeaf->p, iOff, nSz);
+    pIter->bDel = (nSz & 0x0001);
+    pIter->nPos = nSz>>1;
+    pIter->iLeafOffset = iOff;
+  }
+}
+
+static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){
+  u8 *a = pIter->pLeaf->p;        /* Buffer to read data from */
+  int iOff = pIter->iLeafOffset;
+
+  ASSERT_SZLEAF_OK(pIter->pLeaf);
+  if( iOff>=pIter->pLeaf->szLeaf ){
+    fts5SegIterNextPage(p, pIter);
+    if( pIter->pLeaf==0 ){
+      if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT;
+      return;
+    }
+    iOff = 4;
+    a = pIter->pLeaf->p;
+  }
+  iOff += sqlite3Fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid);
+  pIter->iLeafOffset = iOff;
+}
+
+/*
+** Fts5SegIter.iLeafOffset currently points to the first byte of the 
+** "nSuffix" field of a term. Function parameter nKeep contains the value
+** of the "nPrefix" field (if there was one - it is passed 0 if this is
+** the first term in the segment).
+**
+** This function populates:
+**
+**   Fts5SegIter.term
+**   Fts5SegIter.rowid
+**
+** accordingly and leaves (Fts5SegIter.iLeafOffset) set to the content of
+** the first position list. The position list belonging to document 
+** (Fts5SegIter.iRowid).
+*/
+static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){
+  u8 *a = pIter->pLeaf->p;        /* Buffer to read data from */
+  int iOff = pIter->iLeafOffset;  /* Offset to read at */
+  int nNew;                       /* Bytes of new data */
+
+  iOff += fts5GetVarint32(&a[iOff], nNew);
+  pIter->term.n = nKeep;
+  fts5BufferAppendBlob(&p->rc, &pIter->term, nNew, &a[iOff]);
+  iOff += nNew;
+  pIter->iTermLeafOffset = iOff;
+  pIter->iTermLeafPgno = pIter->iLeafPgno;
+  pIter->iLeafOffset = iOff;
+
+  if( pIter->iPgidxOff>=pIter->pLeaf->nn ){
+    pIter->iEndofDoclist = pIter->pLeaf->nn+1;
+  }else{
+    int nExtra;
+    pIter->iPgidxOff += fts5GetVarint32(&a[pIter->iPgidxOff], nExtra);
+    pIter->iEndofDoclist += nExtra;
+  }
+
+  fts5SegIterLoadRowid(p, pIter);
+}
+
+/*
+** Initialize the iterator object pIter to iterate through the entries in
+** segment pSeg. The iterator is left pointing to the first entry when 
+** this function returns.
+**
+** If an error occurs, Fts5Index.rc is set to an appropriate error code. If 
+** an error has already occurred when this function is called, it is a no-op.
+*/
+static void fts5SegIterInit(
+  Fts5Index *p,                   /* FTS index object */
+  Fts5StructureSegment *pSeg,     /* Description of segment */
+  Fts5SegIter *pIter              /* Object to populate */
+){
+  if( pSeg->pgnoFirst==0 ){
+    /* This happens if the segment is being used as an input to an incremental
+    ** merge and all data has already been "trimmed". See function
+    ** fts5TrimSegments() for details. In this case leave the iterator empty.
+    ** The caller will see the (pIter->pLeaf==0) and assume the iterator is
+    ** at EOF already. */
+    assert( pIter->pLeaf==0 );
+    return;
+  }
+
+  if( p->rc==SQLITE_OK ){
+    memset(pIter, 0, sizeof(*pIter));
+    pIter->pSeg = pSeg;
+    pIter->iLeafPgno = pSeg->pgnoFirst-1;
+    fts5SegIterNextPage(p, pIter);
+  }
+
+  if( p->rc==SQLITE_OK ){
+    pIter->iLeafOffset = 4;
+    assert_nc( pIter->pLeaf->nn>4 );
+    assert( fts5LeafFirstTermOff(pIter->pLeaf)==4 );
+    pIter->iPgidxOff = pIter->pLeaf->szLeaf+1;
+    fts5SegIterLoadTerm(p, pIter, 0);
+    fts5SegIterLoadNPos(p, pIter);
+  }
+}
+
+/*
+** This function is only ever called on iterators created by calls to
+** Fts5IndexQuery() with the FTS5INDEX_QUERY_DESC flag set.
+**
+** The iterator is in an unusual state when this function is called: the
+** Fts5SegIter.iLeafOffset variable is set to the offset of the start of
+** the position-list size field for the first relevant rowid on the page.
+** Fts5SegIter.rowid is set, but nPos and bDel are not.
+**
+** This function advances the iterator so that it points to the last 
+** relevant rowid on the page and, if necessary, initializes the 
+** aRowidOffset[] and iRowidOffset variables. At this point the iterator
+** is in its regular state - Fts5SegIter.iLeafOffset points to the first
+** byte of the position list content associated with said rowid.
+*/
+static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
+  int n = pIter->pLeaf->szLeaf;
+  int i = pIter->iLeafOffset;
+  u8 *a = pIter->pLeaf->p;
+  int iRowidOffset = 0;
+
+  if( n>pIter->iEndofDoclist ){
+    n = pIter->iEndofDoclist;
+  }
+
+  ASSERT_SZLEAF_OK(pIter->pLeaf);
+  while( 1 ){
+    i64 iDelta = 0;
+    int nPos;
+    int bDummy;
+
+    i += fts5GetPoslistSize(&a[i], &nPos, &bDummy);
+    i += nPos;
+    if( i>=n ) break;
+    i += fts5GetVarint(&a[i], (u64*)&iDelta);
+    pIter->iRowid += iDelta;
+
+    if( iRowidOffset>=pIter->nRowidOffset ){
+      int nNew = pIter->nRowidOffset + 8;
+      int *aNew = (int*)sqlite3_realloc(pIter->aRowidOffset, nNew*sizeof(int));
+      if( aNew==0 ){
+        p->rc = SQLITE_NOMEM;
+        break;
+      }
+      pIter->aRowidOffset = aNew;
+      pIter->nRowidOffset = nNew;
+    }
+
+    pIter->aRowidOffset[iRowidOffset++] = pIter->iLeafOffset;
+    pIter->iLeafOffset = i;
+  }
+  pIter->iRowidOffset = iRowidOffset;
+  fts5SegIterLoadNPos(p, pIter);
+}
+
+/*
+**
+*/
+static void fts5SegIterReverseNewPage(Fts5Index *p, Fts5SegIter *pIter){
+  assert( pIter->flags & FTS5_SEGITER_REVERSE );
+  assert( pIter->flags & FTS5_SEGITER_ONETERM );
+
+  fts5DataRelease(pIter->pLeaf);
+  pIter->pLeaf = 0;
+  while( p->rc==SQLITE_OK && pIter->iLeafPgno>pIter->iTermLeafPgno ){
+    Fts5Data *pNew;
+    pIter->iLeafPgno--;
+    pNew = fts5DataRead(p, FTS5_SEGMENT_ROWID(
+          pIter->pSeg->iSegid, pIter->iLeafPgno
+    ));
+    if( pNew ){
+      /* iTermLeafOffset may be equal to szLeaf if the term is the last
+      ** thing on the page - i.e. the first rowid is on the following page.
+      ** In this case leaf pIter->pLeaf==0, this iterator is at EOF. */
+      if( pIter->iLeafPgno==pIter->iTermLeafPgno 
+       && pIter->iTermLeafOffset<pNew->szLeaf 
+      ){
+        pIter->pLeaf = pNew;
+        pIter->iLeafOffset = pIter->iTermLeafOffset;
+      }else{
+        int iRowidOff;
+        iRowidOff = fts5LeafFirstRowidOff(pNew);
+        if( iRowidOff ){
+          pIter->pLeaf = pNew;
+          pIter->iLeafOffset = iRowidOff;
+        }
+      }
+
+      if( pIter->pLeaf ){
+        u8 *a = &pIter->pLeaf->p[pIter->iLeafOffset];
+        pIter->iLeafOffset += fts5GetVarint(a, (u64*)&pIter->iRowid);
+        break;
+      }else{
+        fts5DataRelease(pNew);
+      }
+    }
+  }
+
+  if( pIter->pLeaf ){
+    pIter->iEndofDoclist = pIter->pLeaf->nn+1;
+    fts5SegIterReverseInitPage(p, pIter);
+  }
+}
+
+/*
+** Return true if the iterator passed as the second argument currently
+** points to a delete marker. A delete marker is an entry with a 0 byte
+** position-list.
+*/
+static int fts5MultiIterIsEmpty(Fts5Index *p, Fts5IndexIter *pIter){
+  Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
+  return (p->rc==SQLITE_OK && pSeg->pLeaf && pSeg->nPos==0);
+}
+
+/*
+** Advance iterator pIter to the next entry. 
+**
+** If an error occurs, Fts5Index.rc is set to an appropriate error code. It 
+** is not considered an error if the iterator reaches EOF. If an error has 
+** already occurred when this function is called, it is a no-op.
+*/
+static void fts5SegIterNext(
+  Fts5Index *p,                   /* FTS5 backend object */
+  Fts5SegIter *pIter,             /* Iterator to advance */
+  int *pbNewTerm                  /* OUT: Set for new term */
+){
+  assert( pbNewTerm==0 || *pbNewTerm==0 );
+  if( p->rc==SQLITE_OK ){
+    if( pIter->flags & FTS5_SEGITER_REVERSE ){
+      assert( pIter->pNextLeaf==0 );
+      if( pIter->iRowidOffset>0 ){
+        u8 *a = pIter->pLeaf->p;
+        int iOff;
+        int nPos;
+        int bDummy;
+        i64 iDelta;
+
+        pIter->iRowidOffset--;
+        pIter->iLeafOffset = iOff = pIter->aRowidOffset[pIter->iRowidOffset];
+        iOff += fts5GetPoslistSize(&a[iOff], &nPos, &bDummy);
+        iOff += nPos;
+        fts5GetVarint(&a[iOff], (u64*)&iDelta);
+        pIter->iRowid -= iDelta;
+        fts5SegIterLoadNPos(p, pIter);
+      }else{
+        fts5SegIterReverseNewPage(p, pIter);
+      }
+    }else{
+      Fts5Data *pLeaf = pIter->pLeaf;
+      int iOff;
+      int bNewTerm = 0;
+      int nKeep = 0;
+
+      /* Search for the end of the position list within the current page. */
+      u8 *a = pLeaf->p;
+      int n = pLeaf->szLeaf;
+
+      ASSERT_SZLEAF_OK(pLeaf);
+      iOff = pIter->iLeafOffset + pIter->nPos;
+
+      if( iOff<n ){
+        /* The next entry is on the current page. */
+        assert_nc( iOff<=pIter->iEndofDoclist );
+        if( iOff>=pIter->iEndofDoclist ){
+          bNewTerm = 1;
+          if( iOff!=fts5LeafFirstTermOff(pLeaf) ){
+            iOff += fts5GetVarint32(&a[iOff], nKeep);
+          }
+        }else{
+          u64 iDelta;
+          iOff += sqlite3Fts5GetVarint(&a[iOff], &iDelta);
+          pIter->iRowid += iDelta;
+          assert_nc( iDelta>0 );
+        }
+        pIter->iLeafOffset = iOff;
+
+      }else if( pIter->pSeg==0 ){
+        const u8 *pList = 0;
+        const char *zTerm = 0;
+        int nList = 0;
+        if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){
+          sqlite3Fts5HashScanNext(p->pHash);
+          sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
+        }
+        if( pList==0 ){
+          fts5DataRelease(pIter->pLeaf);
+          pIter->pLeaf = 0;
+        }else{
+          pIter->pLeaf->p = (u8*)pList;
+          pIter->pLeaf->nn = nList;
+          pIter->pLeaf->szLeaf = nList;
+          pIter->iEndofDoclist = nList+1;
+          sqlite3Fts5BufferSet(&p->rc, &pIter->term, strlen(zTerm), (u8*)zTerm);
+          pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
+          if( pbNewTerm ) *pbNewTerm = 1;
+        }
+      }else{
+        iOff = 0;
+        /* Next entry is not on the current page */
+        while( iOff==0 ){
+          fts5SegIterNextPage(p, pIter);
+          pLeaf = pIter->pLeaf;
+          if( pLeaf==0 ) break;
+          ASSERT_SZLEAF_OK(pLeaf);
+          if( (iOff = fts5LeafFirstRowidOff(pLeaf)) && iOff<pLeaf->szLeaf ){
+            iOff += sqlite3Fts5GetVarint(&pLeaf->p[iOff], (u64*)&pIter->iRowid);
+            pIter->iLeafOffset = iOff;
+
+            if( pLeaf->nn>pLeaf->szLeaf ){
+              pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
+                  &pLeaf->p[pLeaf->szLeaf], pIter->iEndofDoclist
+              );
+            }
+
+          }
+          else if( pLeaf->nn>pLeaf->szLeaf ){
+            pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
+                &pLeaf->p[pLeaf->szLeaf], iOff
+            );
+            pIter->iLeafOffset = iOff;
+            pIter->iEndofDoclist = iOff;
+            bNewTerm = 1;
+          }
+          if( iOff>=pLeaf->szLeaf ){
+            p->rc = FTS5_CORRUPT;
+            return;
+          }
+        }
+      }
+
+      /* Check if the iterator is now at EOF. If so, return early. */
+      if( pIter->pLeaf ){
+        if( bNewTerm ){
+          if( pIter->flags & FTS5_SEGITER_ONETERM ){
+            fts5DataRelease(pIter->pLeaf);
+            pIter->pLeaf = 0;
+          }else{
+            fts5SegIterLoadTerm(p, pIter, nKeep);
+            fts5SegIterLoadNPos(p, pIter);
+            if( pbNewTerm ) *pbNewTerm = 1;
+          }
+        }else{
+          fts5SegIterLoadNPos(p, pIter);
+        }
+      }
+    }
+  }
+}
+
+#define SWAPVAL(T, a, b) { T tmp; tmp=a; a=b; b=tmp; }
+
+/*
+** Iterator pIter currently points to the first rowid in a doclist. This
+** function sets the iterator up so that iterates in reverse order through
+** the doclist.
+*/
+static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){
+  Fts5DlidxIter *pDlidx = pIter->pDlidx;
+  Fts5Data *pLast = 0;
+  int pgnoLast = 0;
+
+  if( pDlidx ){
+    int iSegid = pIter->pSeg->iSegid;
+    pgnoLast = fts5DlidxIterPgno(pDlidx);
+    pLast = fts5DataRead(p, FTS5_SEGMENT_ROWID(iSegid, pgnoLast));
+  }else{
+    Fts5Data *pLeaf = pIter->pLeaf;         /* Current leaf data */
+
+    /* Currently, Fts5SegIter.iLeafOffset points to the first byte of
+    ** position-list content for the current rowid. Back it up so that it
+    ** points to the start of the position-list size field. */
+    pIter->iLeafOffset -= sqlite3Fts5GetVarintLen(pIter->nPos*2+pIter->bDel);
+
+    /* If this condition is true then the largest rowid for the current
+    ** term may not be stored on the current page. So search forward to
+    ** see where said rowid really is.  */
+    if( pIter->iEndofDoclist>=pLeaf->szLeaf ){
+      int pgno;
+      Fts5StructureSegment *pSeg = pIter->pSeg;
+
+      /* The last rowid in the doclist may not be on the current page. Search
+      ** forward to find the page containing the last rowid.  */
+      for(pgno=pIter->iLeafPgno+1; !p->rc && pgno<=pSeg->pgnoLast; pgno++){
+        i64 iAbs = FTS5_SEGMENT_ROWID(pSeg->iSegid, pgno);
+        Fts5Data *pNew = fts5DataRead(p, iAbs);
+        if( pNew ){
+          int iRowid, bTermless;
+          iRowid = fts5LeafFirstRowidOff(pNew);
+          bTermless = fts5LeafIsTermless(pNew);
+          if( iRowid ){
+            SWAPVAL(Fts5Data*, pNew, pLast);
+            pgnoLast = pgno;
+          }
+          fts5DataRelease(pNew);
+          if( bTermless==0 ) break;
+        }
+      }
+    }
+  }
+
+  /* If pLast is NULL at this point, then the last rowid for this doclist
+  ** lies on the page currently indicated by the iterator. In this case 
+  ** pIter->iLeafOffset is already set to point to the position-list size
+  ** field associated with the first relevant rowid on the page.
+  **
+  ** Or, if pLast is non-NULL, then it is the page that contains the last
+  ** rowid. In this case configure the iterator so that it points to the
+  ** first rowid on this page.
+  */
+  if( pLast ){
+    int iOff;
+    fts5DataRelease(pIter->pLeaf);
+    pIter->pLeaf = pLast;
+    pIter->iLeafPgno = pgnoLast;
+    iOff = fts5LeafFirstRowidOff(pLast);
+    iOff += fts5GetVarint(&pLast->p[iOff], (u64*)&pIter->iRowid);
+    pIter->iLeafOffset = iOff;
+
+    if( fts5LeafIsTermless(pLast) ){
+      pIter->iEndofDoclist = pLast->nn+1;
+    }else{
+      pIter->iEndofDoclist = fts5LeafFirstTermOff(pLast);
+    }
+
+  }
+
+  fts5SegIterReverseInitPage(p, pIter);
+}
+
+/*
+** Iterator pIter currently points to the first rowid of a doclist.
+** There is a doclist-index associated with the final term on the current 
+** page. If the current term is the last term on the page, load the 
+** doclist-index from disk and initialize an iterator at (pIter->pDlidx).
+*/
+static void fts5SegIterLoadDlidx(Fts5Index *p, Fts5SegIter *pIter){
+  int iSeg = pIter->pSeg->iSegid;
+  int bRev = (pIter->flags & FTS5_SEGITER_REVERSE);
+  Fts5Data *pLeaf = pIter->pLeaf; /* Current leaf data */
+
+  assert( pIter->flags & FTS5_SEGITER_ONETERM );
+  assert( pIter->pDlidx==0 );
+
+  /* Check if the current doclist ends on this page. If it does, return
+  ** early without loading the doclist-index (as it belongs to a different
+  ** term. */
+  if( pIter->iTermLeafPgno==pIter->iLeafPgno 
+   && pIter->iEndofDoclist<pLeaf->szLeaf 
+  ){
+    return;
+  }
+
+  pIter->pDlidx = fts5DlidxIterInit(p, bRev, iSeg, pIter->iTermLeafPgno);
+}
+
+#define fts5IndexSkipVarint(a, iOff) {            \
+  int iEnd = iOff+9;                              \
+  while( (a[iOff++] & 0x80) && iOff<iEnd );       \
+}
+
+/*
+** The iterator object passed as the second argument currently contains
+** no valid values except for the Fts5SegIter.pLeaf member variable. This
+** function searches the leaf page for a term matching (pTerm/nTerm).
+**
+** If the specified term is found on the page, then the iterator is left
+** pointing to it. If argument bGe is zero and the term is not found,
+** the iterator is left pointing at EOF.
+**
+** If bGe is non-zero and the specified term is not found, then the
+** iterator is left pointing to the smallest term in the segment that
+** is larger than the specified term, even if this term is not on the
+** current page.
+*/
+static void fts5LeafSeek(
+  Fts5Index *p,                   /* Leave any error code here */
+  int bGe,                        /* True for a >= search */
+  Fts5SegIter *pIter,             /* Iterator to seek */
+  const u8 *pTerm, int nTerm      /* Term to search for */
+){
+  int iOff;
+  const u8 *a = pIter->pLeaf->p;
+  int szLeaf = pIter->pLeaf->szLeaf;
+  int n = pIter->pLeaf->nn;
+
+  int nMatch = 0;
+  int nKeep = 0;
+  int nNew = 0;
+  int iTermOff;
+  int iPgidx;                     /* Current offset in pgidx */
+  int bEndOfPage = 0;
+
+  assert( p->rc==SQLITE_OK );
+
+  iPgidx = szLeaf;
+  iPgidx += fts5GetVarint32(&a[iPgidx], iTermOff);
+  iOff = iTermOff;
+
+  while( 1 ){
+
+    /* Figure out how many new bytes are in this term */
+    fts5FastGetVarint32(a, iOff, nNew);
+    if( nKeep<nMatch ){
+      goto search_failed;
+    }
+
+    assert( nKeep>=nMatch );
+    if( nKeep==nMatch ){
+      int nCmp;
+      int i;
+      nCmp = MIN(nNew, nTerm-nMatch);
+      for(i=0; i<nCmp; i++){
+        if( a[iOff+i]!=pTerm[nMatch+i] ) break;
+      }
+      nMatch += i;
+
+      if( nTerm==nMatch ){
+        if( i==nNew ){
+          goto search_success;
+        }else{
+          goto search_failed;
+        }
+      }else if( i<nNew && a[iOff+i]>pTerm[nMatch] ){
+        goto search_failed;
+      }
+    }
+
+    if( iPgidx>=n ){
+      bEndOfPage = 1;
+      break;
+    }
+
+    iPgidx += fts5GetVarint32(&a[iPgidx], nKeep);
+    iTermOff += nKeep;
+    iOff = iTermOff;
+
+    /* Read the nKeep field of the next term. */
+    fts5FastGetVarint32(a, iOff, nKeep);
+  }
+
+ search_failed:
+  if( bGe==0 ){
+    fts5DataRelease(pIter->pLeaf);
+    pIter->pLeaf = 0;
+    return;
+  }else if( bEndOfPage ){
+    do {
+      fts5SegIterNextPage(p, pIter);
+      if( pIter->pLeaf==0 ) return;
+      a = pIter->pLeaf->p;
+      if( fts5LeafIsTermless(pIter->pLeaf)==0 ){
+        fts5GetVarint32(&pIter->pLeaf->p[pIter->pLeaf->szLeaf], iOff);
+        if( iOff<4 || iOff>=pIter->pLeaf->szLeaf ){
+          p->rc = FTS5_CORRUPT;
+        }else{
+          nKeep = 0;
+          iOff += fts5GetVarint32(&a[iOff], nNew);
+          break;
+        }
+      }
+    }while( 1 );
+  }
+
+ search_success:
+
+  pIter->iLeafOffset = iOff + nNew;
+  pIter->iTermLeafOffset = pIter->iLeafOffset;
+  pIter->iTermLeafPgno = pIter->iLeafPgno;
+
+  fts5BufferSet(&p->rc, &pIter->term, nKeep, pTerm);
+  fts5BufferAppendBlob(&p->rc, &pIter->term, nNew, &a[iOff]);
+
+  if( iPgidx>=n ){
+    pIter->iEndofDoclist = pIter->pLeaf->nn+1;
+  }else{
+    int nExtra;
+    iPgidx += fts5GetVarint32(&a[iPgidx], nExtra);
+    pIter->iEndofDoclist = iTermOff + nExtra;
+  }
+  pIter->iPgidxOff = iPgidx;
+
+  fts5SegIterLoadRowid(p, pIter);
+  fts5SegIterLoadNPos(p, pIter);
+}
+
+/*
+** Initialize the object pIter to point to term pTerm/nTerm within segment
+** pSeg. If there is no such term in the index, the iterator is set to EOF.
+**
+** If an error occurs, Fts5Index.rc is set to an appropriate error code. If 
+** an error has already occurred when this function is called, it is a no-op.
+*/
+static void fts5SegIterSeekInit(
+  Fts5Index *p,                   /* FTS5 backend */
+  Fts5Buffer *pBuf,               /* Buffer to use for loading pages */
+  const u8 *pTerm, int nTerm,     /* Term to seek to */
+  int flags,                      /* Mask of FTS5INDEX_XXX flags */
+  Fts5StructureSegment *pSeg,     /* Description of segment */
+  Fts5SegIter *pIter              /* Object to populate */
+){
+  int iPg = 1;
+  int bGe = (flags & FTS5INDEX_QUERY_SCAN);
+  int bDlidx = 0;                 /* True if there is a doclist-index */
+
+  static int nCall = 0;
+  nCall++;
+
+  assert( bGe==0 || (flags & FTS5INDEX_QUERY_DESC)==0 );
+  assert( pTerm && nTerm );
+  memset(pIter, 0, sizeof(*pIter));
+  pIter->pSeg = pSeg;
+
+  /* This block sets stack variable iPg to the leaf page number that may
+  ** contain term (pTerm/nTerm), if it is present in the segment. */
+  if( p->pIdxSelect==0 ){
+    Fts5Config *pConfig = p->pConfig;
+    fts5IndexPrepareStmt(p, &p->pIdxSelect, sqlite3_mprintf(
+          "SELECT pgno FROM '%q'.'%q_idx' WHERE "
+          "segid=? AND term<=? ORDER BY term DESC LIMIT 1",
+          pConfig->zDb, pConfig->zName
+    ));
+  }
+  if( p->rc ) return;
+  sqlite3_bind_int(p->pIdxSelect, 1, pSeg->iSegid);
+  sqlite3_bind_blob(p->pIdxSelect, 2, pTerm, nTerm, SQLITE_STATIC);
+  if( SQLITE_ROW==sqlite3_step(p->pIdxSelect) ){
+    i64 val = sqlite3_column_int(p->pIdxSelect, 0);
+    iPg = (int)(val>>1);
+    bDlidx = (val & 0x0001);
+  }
+  p->rc = sqlite3_reset(p->pIdxSelect);
+
+  if( iPg<pSeg->pgnoFirst ){
+    iPg = pSeg->pgnoFirst;
+    bDlidx = 0;
+  }
+
+  pIter->iLeafPgno = iPg - 1;
+  fts5SegIterNextPage(p, pIter);
+
+  if( pIter->pLeaf ){
+    fts5LeafSeek(p, bGe, pIter, pTerm, nTerm);
+  }
+
+  if( p->rc==SQLITE_OK && bGe==0 ){
+    pIter->flags |= FTS5_SEGITER_ONETERM;
+    if( pIter->pLeaf ){
+      if( flags & FTS5INDEX_QUERY_DESC ){
+        pIter->flags |= FTS5_SEGITER_REVERSE;
+      }
+      if( bDlidx ){
+        fts5SegIterLoadDlidx(p, pIter);
+      }
+      if( flags & FTS5INDEX_QUERY_DESC ){
+        fts5SegIterReverse(p, pIter);
+      }
+    }
+  }
+
+  /* Either:
+  **
+  **   1) an error has occurred, or
+  **   2) the iterator points to EOF, or
+  **   3) the iterator points to an entry with term (pTerm/nTerm), or
+  **   4) the FTS5INDEX_QUERY_SCAN flag was set and the iterator points
+  **      to an entry with a term greater than or equal to (pTerm/nTerm).
+  */
+  assert( p->rc!=SQLITE_OK                                          /* 1 */
+   || pIter->pLeaf==0                                               /* 2 */
+   || fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)==0          /* 3 */
+   || (bGe && fts5BufferCompareBlob(&pIter->term, pTerm, nTerm)>0)  /* 4 */
+  );
+}
+
+/*
+** Initialize the object pIter to point to term pTerm/nTerm within the
+** in-memory hash table. If there is no such term in the hash-table, the 
+** iterator is set to EOF.
+**
+** If an error occurs, Fts5Index.rc is set to an appropriate error code. If 
+** an error has already occurred when this function is called, it is a no-op.
+*/
+static void fts5SegIterHashInit(
+  Fts5Index *p,                   /* FTS5 backend */
+  const u8 *pTerm, int nTerm,     /* Term to seek to */
+  int flags,                      /* Mask of FTS5INDEX_XXX flags */
+  Fts5SegIter *pIter              /* Object to populate */
+){
+  const u8 *pList = 0;
+  int nList = 0;
+  const u8 *z = 0;
+  int n = 0;
+
+  assert( p->pHash );
+  assert( p->rc==SQLITE_OK );
+
+  if( pTerm==0 || (flags & FTS5INDEX_QUERY_SCAN) ){
+    p->rc = sqlite3Fts5HashScanInit(p->pHash, (const char*)pTerm, nTerm);
+    sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &pList, &nList);
+    n = (z ? strlen((const char*)z) : 0);
+  }else{
+    pIter->flags |= FTS5_SEGITER_ONETERM;
+    sqlite3Fts5HashQuery(p->pHash, (const char*)pTerm, nTerm, &pList, &nList);
+    z = pTerm;
+    n = nTerm;
+  }
+
+  if( pList ){
+    Fts5Data *pLeaf;
+    sqlite3Fts5BufferSet(&p->rc, &pIter->term, n, z);
+    pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data));
+    if( pLeaf==0 ) return;
+    pLeaf->p = (u8*)pList;
+    pLeaf->nn = pLeaf->szLeaf = nList;
+    pIter->pLeaf = pLeaf;
+    pIter->iLeafOffset = fts5GetVarint(pLeaf->p, (u64*)&pIter->iRowid);
+    pIter->iEndofDoclist = pLeaf->nn+1;
+
+    if( flags & FTS5INDEX_QUERY_DESC ){
+      pIter->flags |= FTS5_SEGITER_REVERSE;
+      fts5SegIterReverseInitPage(p, pIter);
+    }else{
+      fts5SegIterLoadNPos(p, pIter);
+    }
+  }
+}
+
+/*
+** Zero the iterator passed as the only argument.
+*/
+static void fts5SegIterClear(Fts5SegIter *pIter){
+  fts5BufferFree(&pIter->term);
+  fts5DataRelease(pIter->pLeaf);
+  fts5DataRelease(pIter->pNextLeaf);
+  fts5DlidxIterFree(pIter->pDlidx);
+  sqlite3_free(pIter->aRowidOffset);
+  memset(pIter, 0, sizeof(Fts5SegIter));
+}
+
+#ifdef SQLITE_DEBUG
+
+/*
+** This function is used as part of the big assert() procedure implemented by
+** fts5AssertMultiIterSetup(). It ensures that the result currently stored
+** in *pRes is the correct result of comparing the current positions of the
+** two iterators.
+*/
+static void fts5AssertComparisonResult(
+  Fts5IndexIter *pIter, 
+  Fts5SegIter *p1,
+  Fts5SegIter *p2,
+  Fts5CResult *pRes
+){
+  int i1 = p1 - pIter->aSeg;
+  int i2 = p2 - pIter->aSeg;
+
+  if( p1->pLeaf || p2->pLeaf ){
+    if( p1->pLeaf==0 ){
+      assert( pRes->iFirst==i2 );
+    }else if( p2->pLeaf==0 ){
+      assert( pRes->iFirst==i1 );
+    }else{
+      int nMin = MIN(p1->term.n, p2->term.n);
+      int res = memcmp(p1->term.p, p2->term.p, nMin);
+      if( res==0 ) res = p1->term.n - p2->term.n;
+
+      if( res==0 ){
+        assert( pRes->bTermEq==1 );
+        assert( p1->iRowid!=p2->iRowid );
+        res = ((p1->iRowid > p2->iRowid)==pIter->bRev) ? -1 : 1;
+      }else{
+        assert( pRes->bTermEq==0 );
+      }
+
+      if( res<0 ){
+        assert( pRes->iFirst==i1 );
+      }else{
+        assert( pRes->iFirst==i2 );
+      }
+    }
+  }
+}
+
+/*
+** This function is a no-op unless SQLITE_DEBUG is defined when this module
+** is compiled. In that case, this function is essentially an assert() 
+** statement used to verify that the contents of the pIter->aFirst[] array
+** are correct.
+*/
+static void fts5AssertMultiIterSetup(Fts5Index *p, Fts5IndexIter *pIter){
+  if( p->rc==SQLITE_OK ){
+    Fts5SegIter *pFirst = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
+    int i;
+
+    assert( (pFirst->pLeaf==0)==pIter->bEof );
+
+    /* Check that pIter->iSwitchRowid is set correctly. */
+    for(i=0; i<pIter->nSeg; i++){
+      Fts5SegIter *p1 = &pIter->aSeg[i];
+      assert( p1==pFirst 
+           || p1->pLeaf==0 
+           || fts5BufferCompare(&pFirst->term, &p1->term) 
+           || p1->iRowid==pIter->iSwitchRowid
+           || (p1->iRowid<pIter->iSwitchRowid)==pIter->bRev
+      );
+    }
+
+    for(i=0; i<pIter->nSeg; i+=2){
+      Fts5SegIter *p1 = &pIter->aSeg[i];
+      Fts5SegIter *p2 = &pIter->aSeg[i+1];
+      Fts5CResult *pRes = &pIter->aFirst[(pIter->nSeg + i) / 2];
+      fts5AssertComparisonResult(pIter, p1, p2, pRes);
+    }
+
+    for(i=1; i<(pIter->nSeg / 2); i+=2){
+      Fts5SegIter *p1 = &pIter->aSeg[ pIter->aFirst[i*2].iFirst ];
+      Fts5SegIter *p2 = &pIter->aSeg[ pIter->aFirst[i*2+1].iFirst ];
+      Fts5CResult *pRes = &pIter->aFirst[i];
+      fts5AssertComparisonResult(pIter, p1, p2, pRes);
+    }
+  }
+}
+#else
+# define fts5AssertMultiIterSetup(x,y)
+#endif
+
+/*
+** Do the comparison necessary to populate pIter->aFirst[iOut].
+**
+** If the returned value is non-zero, then it is the index of an entry
+** in the pIter->aSeg[] array that is (a) not at EOF, and (b) pointing
+** to a key that is a duplicate of another, higher priority, 
+** segment-iterator in the pSeg->aSeg[] array.
+*/
+static int fts5MultiIterDoCompare(Fts5IndexIter *pIter, int iOut){
+  int i1;                         /* Index of left-hand Fts5SegIter */
+  int i2;                         /* Index of right-hand Fts5SegIter */
+  int iRes;
+  Fts5SegIter *p1;                /* Left-hand Fts5SegIter */
+  Fts5SegIter *p2;                /* Right-hand Fts5SegIter */
+  Fts5CResult *pRes = &pIter->aFirst[iOut];
+
+  assert( iOut<pIter->nSeg && iOut>0 );
+  assert( pIter->bRev==0 || pIter->bRev==1 );
+
+  if( iOut>=(pIter->nSeg/2) ){
+    i1 = (iOut - pIter->nSeg/2) * 2;
+    i2 = i1 + 1;
+  }else{
+    i1 = pIter->aFirst[iOut*2].iFirst;
+    i2 = pIter->aFirst[iOut*2+1].iFirst;
+  }
+  p1 = &pIter->aSeg[i1];
+  p2 = &pIter->aSeg[i2];
+
+  pRes->bTermEq = 0;
+  if( p1->pLeaf==0 ){           /* If p1 is at EOF */
+    iRes = i2;
+  }else if( p2->pLeaf==0 ){     /* If p2 is at EOF */
+    iRes = i1;
+  }else{
+    int res = fts5BufferCompare(&p1->term, &p2->term);
+    if( res==0 ){
+      assert( i2>i1 );
+      assert( i2!=0 );
+      pRes->bTermEq = 1;
+      if( p1->iRowid==p2->iRowid ){
+        p1->bDel = p2->bDel;
+        return i2;
+      }
+      res = ((p1->iRowid > p2->iRowid)==pIter->bRev) ? -1 : +1;
+    }
+    assert( res!=0 );
+    if( res<0 ){
+      iRes = i1;
+    }else{
+      iRes = i2;
+    }
+  }
+
+  pRes->iFirst = iRes;
+  return 0;
+}
+
+/*
+** Move the seg-iter so that it points to the first rowid on page iLeafPgno.
+** It is an error if leaf iLeafPgno does not exist or contains no rowids.
+*/
+static void fts5SegIterGotoPage(
+  Fts5Index *p,                   /* FTS5 backend object */
+  Fts5SegIter *pIter,             /* Iterator to advance */
+  int iLeafPgno
+){
+  assert( iLeafPgno>pIter->iLeafPgno );
+
+  if( iLeafPgno>pIter->pSeg->pgnoLast ){
+    p->rc = FTS5_CORRUPT;
+  }else{
+    fts5DataRelease(pIter->pNextLeaf);
+    pIter->pNextLeaf = 0;
+    pIter->iLeafPgno = iLeafPgno-1;
+    fts5SegIterNextPage(p, pIter);
+    assert( p->rc!=SQLITE_OK || pIter->iLeafPgno==iLeafPgno );
+
+    if( p->rc==SQLITE_OK ){
+      int iOff;
+      u8 *a = pIter->pLeaf->p;
+      int n = pIter->pLeaf->szLeaf;
+
+      iOff = fts5LeafFirstRowidOff(pIter->pLeaf);
+      if( iOff<4 || iOff>=n ){
+        p->rc = FTS5_CORRUPT;
+      }else{
+        iOff += fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid);
+        pIter->iLeafOffset = iOff;
+        fts5SegIterLoadNPos(p, pIter);
+      }
+    }
+  }
+}
+
+/*
+** Advance the iterator passed as the second argument until it is at or 
+** past rowid iFrom. Regardless of the value of iFrom, the iterator is
+** always advanced at least once.
+*/
+static void fts5SegIterNextFrom(
+  Fts5Index *p,                   /* FTS5 backend object */
+  Fts5SegIter *pIter,             /* Iterator to advance */
+  i64 iMatch                      /* Advance iterator at least this far */
+){
+  int bRev = (pIter->flags & FTS5_SEGITER_REVERSE);
+  Fts5DlidxIter *pDlidx = pIter->pDlidx;
+  int iLeafPgno = pIter->iLeafPgno;
+  int bMove = 1;
+
+  assert( pIter->flags & FTS5_SEGITER_ONETERM );
+  assert( pIter->pDlidx );
+  assert( pIter->pLeaf );
+
+  if( bRev==0 ){
+    while( !fts5DlidxIterEof(p, pDlidx) && iMatch>fts5DlidxIterRowid(pDlidx) ){
+      iLeafPgno = fts5DlidxIterPgno(pDlidx);
+      fts5DlidxIterNext(p, pDlidx);
+    }
+    assert_nc( iLeafPgno>=pIter->iLeafPgno || p->rc );
+    if( iLeafPgno>pIter->iLeafPgno ){
+      fts5SegIterGotoPage(p, pIter, iLeafPgno);
+      bMove = 0;
+    }
+  }else{
+    assert( pIter->pNextLeaf==0 );
+    assert( iMatch<pIter->iRowid );
+    while( !fts5DlidxIterEof(p, pDlidx) && iMatch<fts5DlidxIterRowid(pDlidx) ){
+      fts5DlidxIterPrev(p, pDlidx);
+    }
+    iLeafPgno = fts5DlidxIterPgno(pDlidx);
+
+    assert( fts5DlidxIterEof(p, pDlidx) || iLeafPgno<=pIter->iLeafPgno );
+
+    if( iLeafPgno<pIter->iLeafPgno ){
+      pIter->iLeafPgno = iLeafPgno+1;
+      fts5SegIterReverseNewPage(p, pIter);
+      bMove = 0;
+    }
+  }
+
+  do{
+    if( bMove ) fts5SegIterNext(p, pIter, 0);
+    if( pIter->pLeaf==0 ) break;
+    if( bRev==0 && pIter->iRowid>=iMatch ) break;
+    if( bRev!=0 && pIter->iRowid<=iMatch ) break;
+    bMove = 1;
+  }while( p->rc==SQLITE_OK );
+}
+
+
+/*
+** Free the iterator object passed as the second argument.
+*/
+static void fts5MultiIterFree(Fts5Index *p, Fts5IndexIter *pIter){
+  if( pIter ){
+    int i;
+    for(i=0; i<pIter->nSeg; i++){
+      fts5SegIterClear(&pIter->aSeg[i]);
+    }
+    fts5StructureRelease(pIter->pStruct);
+    fts5BufferFree(&pIter->poslist);
+    sqlite3_free(pIter);
+  }
+}
+
+static void fts5MultiIterAdvanced(
+  Fts5Index *p,                   /* FTS5 backend to iterate within */
+  Fts5IndexIter *pIter,           /* Iterator to update aFirst[] array for */
+  int iChanged,                   /* Index of sub-iterator just advanced */
+  int iMinset                     /* Minimum entry in aFirst[] to set */
+){
+  int i;
+  for(i=(pIter->nSeg+iChanged)/2; i>=iMinset && p->rc==SQLITE_OK; i=i/2){
+    int iEq;
+    if( (iEq = fts5MultiIterDoCompare(pIter, i)) ){
+      fts5SegIterNext(p, &pIter->aSeg[iEq], 0);
+      i = pIter->nSeg + iEq;
+    }
+  }
+}
+
+/*
+** Sub-iterator iChanged of iterator pIter has just been advanced. It still
+** points to the same term though - just a different rowid. This function
+** attempts to update the contents of the pIter->aFirst[] accordingly.
+** If it does so successfully, 0 is returned. Otherwise 1.
+**
+** If non-zero is returned, the caller should call fts5MultiIterAdvanced()
+** on the iterator instead. That function does the same as this one, except
+** that it deals with more complicated cases as well.
+*/ 
+static int fts5MultiIterAdvanceRowid(
+  Fts5Index *p,                   /* FTS5 backend to iterate within */
+  Fts5IndexIter *pIter,           /* Iterator to update aFirst[] array for */
+  int iChanged                    /* Index of sub-iterator just advanced */
+){
+  Fts5SegIter *pNew = &pIter->aSeg[iChanged];
+
+  if( pNew->iRowid==pIter->iSwitchRowid
+   || (pNew->iRowid<pIter->iSwitchRowid)==pIter->bRev
+  ){
+    int i;
+    Fts5SegIter *pOther = &pIter->aSeg[iChanged ^ 0x0001];
+    pIter->iSwitchRowid = pIter->bRev ? SMALLEST_INT64 : LARGEST_INT64;
+    for(i=(pIter->nSeg+iChanged)/2; 1; i=i/2){
+      Fts5CResult *pRes = &pIter->aFirst[i];
+
+      assert( pNew->pLeaf );
+      assert( pRes->bTermEq==0 || pOther->pLeaf );
+
+      if( pRes->bTermEq ){
+        if( pNew->iRowid==pOther->iRowid ){
+          return 1;
+        }else if( (pOther->iRowid>pNew->iRowid)==pIter->bRev ){
+          pIter->iSwitchRowid = pOther->iRowid;
+          pNew = pOther;
+        }else if( (pOther->iRowid>pIter->iSwitchRowid)==pIter->bRev ){
+          pIter->iSwitchRowid = pOther->iRowid;
+        }
+      }
+      pRes->iFirst = (pNew - pIter->aSeg);
+      if( i==1 ) break;
+
+      pOther = &pIter->aSeg[ pIter->aFirst[i ^ 0x0001].iFirst ];
+    }
+  }
+
+  return 0;
+}
+
+/*
+** Set the pIter->bEof variable based on the state of the sub-iterators.
+*/
+static void fts5MultiIterSetEof(Fts5IndexIter *pIter){
+  Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
+  pIter->bEof = pSeg->pLeaf==0;
+  pIter->iSwitchRowid = pSeg->iRowid;
+}
+
+/*
+** Move the iterator to the next entry. 
+**
+** If an error occurs, an error code is left in Fts5Index.rc. It is not 
+** considered an error if the iterator reaches EOF, or if it is already at 
+** EOF when this function is called.
+*/
+static void fts5MultiIterNext(
+  Fts5Index *p, 
+  Fts5IndexIter *pIter,
+  int bFrom,                      /* True if argument iFrom is valid */
+  i64 iFrom                       /* Advance at least as far as this */
+){
+  if( p->rc==SQLITE_OK ){
+    int bUseFrom = bFrom;
+    do {
+      int iFirst = pIter->aFirst[1].iFirst;
+      int bNewTerm = 0;
+      Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
+      assert( p->rc==SQLITE_OK );
+      if( bUseFrom && pSeg->pDlidx ){
+        fts5SegIterNextFrom(p, pSeg, iFrom);
+      }else{
+        fts5SegIterNext(p, pSeg, &bNewTerm);
+      }
+
+      if( pSeg->pLeaf==0 || bNewTerm 
+       || fts5MultiIterAdvanceRowid(p, pIter, iFirst)
+      ){
+        fts5MultiIterAdvanced(p, pIter, iFirst, 1);
+        fts5MultiIterSetEof(pIter);
+      }
+      fts5AssertMultiIterSetup(p, pIter);
+
+      bUseFrom = 0;
+    }while( pIter->bSkipEmpty && fts5MultiIterIsEmpty(p, pIter) );
+  }
+}
+
+static Fts5IndexIter *fts5MultiIterAlloc(
+  Fts5Index *p,                   /* FTS5 backend to iterate within */
+  int nSeg
+){
+  Fts5IndexIter *pNew;
+  int nSlot;                      /* Power of two >= nSeg */
+
+  for(nSlot=2; nSlot<nSeg; nSlot=nSlot*2);
+  pNew = fts5IdxMalloc(p, 
+      sizeof(Fts5IndexIter) +             /* pNew */
+      sizeof(Fts5SegIter) * (nSlot-1) +   /* pNew->aSeg[] */
+      sizeof(Fts5CResult) * nSlot         /* pNew->aFirst[] */
+  );
+  if( pNew ){
+    pNew->nSeg = nSlot;
+    pNew->aFirst = (Fts5CResult*)&pNew->aSeg[nSlot];
+    pNew->pIndex = p;
+  }
+  return pNew;
+}
+
+/*
+** Allocate a new Fts5IndexIter object.
+**
+** The new object will be used to iterate through data in structure pStruct.
+** If iLevel is -ve, then all data in all segments is merged. Or, if iLevel
+** is zero or greater, data from the first nSegment segments on level iLevel
+** is merged.
+**
+** The iterator initially points to the first term/rowid entry in the 
+** iterated data.
+*/
+static void fts5MultiIterNew(
+  Fts5Index *p,                   /* FTS5 backend to iterate within */
+  Fts5Structure *pStruct,         /* Structure of specific index */
+  int bSkipEmpty,                 /* True to ignore delete-keys */
+  int flags,                      /* FTS5INDEX_QUERY_XXX flags */
+  const u8 *pTerm, int nTerm,     /* Term to seek to (or NULL/0) */
+  int iLevel,                     /* Level to iterate (-1 for all) */
+  int nSegment,                   /* Number of segments to merge (iLevel>=0) */
+  Fts5IndexIter **ppOut           /* New object */
+){
+  int nSeg = 0;                   /* Number of segment-iters in use */
+  int iIter = 0;                  /* */
+  int iSeg;                       /* Used to iterate through segments */
+  Fts5Buffer buf = {0,0,0};       /* Buffer used by fts5SegIterSeekInit() */
+  Fts5StructureLevel *pLvl;
+  Fts5IndexIter *pNew;
+
+  assert( (pTerm==0 && nTerm==0) || iLevel<0 );
+
+  /* Allocate space for the new multi-seg-iterator. */
+  if( p->rc==SQLITE_OK ){
+    if( iLevel<0 ){
+      assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) );
+      nSeg = pStruct->nSegment;
+      nSeg += (p->pHash ? 1 : 0);
+    }else{
+      nSeg = MIN(pStruct->aLevel[iLevel].nSeg, nSegment);
+    }
+  }
+  *ppOut = pNew = fts5MultiIterAlloc(p, nSeg);
+  if( pNew==0 ) return;
+  pNew->bRev = (0!=(flags & FTS5INDEX_QUERY_DESC));
+  pNew->bSkipEmpty = bSkipEmpty;
+  pNew->pStruct = pStruct;
+  fts5StructureRef(pStruct);
+
+  /* Initialize each of the component segment iterators. */
+  if( iLevel<0 ){
+    Fts5StructureLevel *pEnd = &pStruct->aLevel[pStruct->nLevel];
+    if( p->pHash ){
+      /* Add a segment iterator for the current contents of the hash table. */
+      Fts5SegIter *pIter = &pNew->aSeg[iIter++];
+      fts5SegIterHashInit(p, pTerm, nTerm, flags, pIter);
+    }
+    for(pLvl=&pStruct->aLevel[0]; pLvl<pEnd; pLvl++){
+      for(iSeg=pLvl->nSeg-1; iSeg>=0; iSeg--){
+        Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg];
+        Fts5SegIter *pIter = &pNew->aSeg[iIter++];
+        if( pTerm==0 ){
+          fts5SegIterInit(p, pSeg, pIter);
+        }else{
+          fts5SegIterSeekInit(p, &buf, pTerm, nTerm, flags, pSeg, pIter);
+        }
+      }
+    }
+  }else{
+    pLvl = &pStruct->aLevel[iLevel];
+    for(iSeg=nSeg-1; iSeg>=0; iSeg--){
+      fts5SegIterInit(p, &pLvl->aSeg[iSeg], &pNew->aSeg[iIter++]);
+    }
+  }
+  assert( iIter==nSeg );
+
+  /* If the above was successful, each component iterators now points 
+  ** to the first entry in its segment. In this case initialize the 
+  ** aFirst[] array. Or, if an error has occurred, free the iterator
+  ** object and set the output variable to NULL.  */
+  if( p->rc==SQLITE_OK ){
+    for(iIter=pNew->nSeg-1; iIter>0; iIter--){
+      int iEq;
+      if( (iEq = fts5MultiIterDoCompare(pNew, iIter)) ){
+        fts5SegIterNext(p, &pNew->aSeg[iEq], 0);
+        fts5MultiIterAdvanced(p, pNew, iEq, iIter);
+      }
+    }
+    fts5MultiIterSetEof(pNew);
+    fts5AssertMultiIterSetup(p, pNew);
+
+    if( pNew->bSkipEmpty && fts5MultiIterIsEmpty(p, pNew) ){
+      fts5MultiIterNext(p, pNew, 0, 0);
+    }
+  }else{
+    fts5MultiIterFree(p, pNew);
+    *ppOut = 0;
+  }
+  fts5BufferFree(&buf);
+}
+
+/*
+** Create an Fts5IndexIter that iterates through the doclist provided
+** as the second argument.
+*/
+static void fts5MultiIterNew2(
+  Fts5Index *p,                   /* FTS5 backend to iterate within */
+  Fts5Data *pData,                /* Doclist to iterate through */
+  int bDesc,                      /* True for descending rowid order */
+  Fts5IndexIter **ppOut           /* New object */
+){
+  Fts5IndexIter *pNew;
+  pNew = fts5MultiIterAlloc(p, 2);
+  if( pNew ){
+    Fts5SegIter *pIter = &pNew->aSeg[1];
+
+    pNew->bFiltered = 1;
+    pIter->flags = FTS5_SEGITER_ONETERM;
+    if( pData->szLeaf>0 ){
+      pIter->pLeaf = pData;
+      pIter->iLeafOffset = fts5GetVarint(pData->p, (u64*)&pIter->iRowid);
+      pIter->iEndofDoclist = pData->nn;
+      pNew->aFirst[1].iFirst = 1;
+      if( bDesc ){
+        pNew->bRev = 1;
+        pIter->flags |= FTS5_SEGITER_REVERSE;
+        fts5SegIterReverseInitPage(p, pIter);
+      }else{
+        fts5SegIterLoadNPos(p, pIter);
+      }
+      pData = 0;
+    }else{
+      pNew->bEof = 1;
+    }
+
+    *ppOut = pNew;
+  }
+
+  fts5DataRelease(pData);
+}
+
+/*
+** Return true if the iterator is at EOF or if an error has occurred. 
+** False otherwise.
+*/
+static int fts5MultiIterEof(Fts5Index *p, Fts5IndexIter *pIter){
+  assert( p->rc 
+      || (pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf==0)==pIter->bEof 
+  );
+  return (p->rc || pIter->bEof);
+}
+
+/*
+** Return the rowid of the entry that the iterator currently points
+** to. If the iterator points to EOF when this function is called the
+** results are undefined.
+*/
+static i64 fts5MultiIterRowid(Fts5IndexIter *pIter){
+  assert( pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf );
+  return pIter->aSeg[ pIter->aFirst[1].iFirst ].iRowid;
+}
+
+/*
+** Move the iterator to the next entry at or following iMatch.
+*/
+static void fts5MultiIterNextFrom(
+  Fts5Index *p, 
+  Fts5IndexIter *pIter, 
+  i64 iMatch
+){
+  while( 1 ){
+    i64 iRowid;
+    fts5MultiIterNext(p, pIter, 1, iMatch);
+    if( fts5MultiIterEof(p, pIter) ) break;
+    iRowid = fts5MultiIterRowid(pIter);
+    if( pIter->bRev==0 && iRowid>=iMatch ) break;
+    if( pIter->bRev!=0 && iRowid<=iMatch ) break;
+  }
+}
+
+/*
+** Return a pointer to a buffer containing the term associated with the 
+** entry that the iterator currently points to.
+*/
+static const u8 *fts5MultiIterTerm(Fts5IndexIter *pIter, int *pn){
+  Fts5SegIter *p = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
+  *pn = p->term.n;
+  return p->term.p;
+}
+
+static void fts5ChunkIterate(
+  Fts5Index *p,                   /* Index object */
+  Fts5SegIter *pSeg,              /* Poslist of this iterator */
+  void *pCtx,                     /* Context pointer for xChunk callback */
+  void (*xChunk)(Fts5Index*, void*, const u8*, int)
+){
+  int nRem = pSeg->nPos;          /* Number of bytes still to come */
+  Fts5Data *pData = 0;
+  u8 *pChunk = &pSeg->pLeaf->p[pSeg->iLeafOffset];
+  int nChunk = MIN(nRem, pSeg->pLeaf->szLeaf - pSeg->iLeafOffset);
+  int pgno = pSeg->iLeafPgno;
+  int pgnoSave = 0;
+
+  if( (pSeg->flags & FTS5_SEGITER_REVERSE)==0 ){
+    pgnoSave = pgno+1;
+  }
+
+  while( 1 ){
+    xChunk(p, pCtx, pChunk, nChunk);
+    nRem -= nChunk;
+    fts5DataRelease(pData);
+    if( nRem<=0 ){
+      break;
+    }else{
+      pgno++;
+      pData = fts5DataRead(p, FTS5_SEGMENT_ROWID(pSeg->pSeg->iSegid, pgno));
+      if( pData==0 ) break;
+      pChunk = &pData->p[4];
+      nChunk = MIN(nRem, pData->szLeaf - 4);
+      if( pgno==pgnoSave ){
+        assert( pSeg->pNextLeaf==0 );
+        pSeg->pNextLeaf = pData;
+        pData = 0;
+      }
+    }
+  }
+}
+
+
+
+/*
+** Allocate a new segment-id for the structure pStruct. The new segment
+** id must be between 1 and 65335 inclusive, and must not be used by 
+** any currently existing segment. If a free segment id cannot be found,
+** SQLITE_FULL is returned.
+**
+** If an error has already occurred, this function is a no-op. 0 is 
+** returned in this case.
+*/
+static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){
+  int iSegid = 0;
+
+  if( p->rc==SQLITE_OK ){
+    if( pStruct->nSegment>=FTS5_MAX_SEGMENT ){
+      p->rc = SQLITE_FULL;
+    }else{
+      while( iSegid==0 ){
+        int iLvl, iSeg;
+        sqlite3_randomness(sizeof(u32), (void*)&iSegid);
+        iSegid = iSegid & ((1 << FTS5_DATA_ID_B)-1);
+        for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
+          for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
+            if( iSegid==pStruct->aLevel[iLvl].aSeg[iSeg].iSegid ){
+              iSegid = 0;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  return iSegid;
+}
+
+/*
+** Discard all data currently cached in the hash-tables.
+*/
+static void fts5IndexDiscardData(Fts5Index *p){
+  assert( p->pHash || p->nPendingData==0 );
+  if( p->pHash ){
+    sqlite3Fts5HashClear(p->pHash);
+    p->nPendingData = 0;
+  }
+}
+
+/*
+** Return the size of the prefix, in bytes, that buffer (nNew/pNew) shares
+** with buffer (nOld/pOld).
+*/
+static int fts5PrefixCompress(
+  int nOld, const u8 *pOld,
+  int nNew, const u8 *pNew
+){
+  int i;
+  assert( fts5BlobCompare(pOld, nOld, pNew, nNew)<0 );
+  for(i=0; i<nOld; i++){
+    if( pOld[i]!=pNew[i] ) break;
+  }
+  return i;
+}
+
+static void fts5WriteDlidxClear(
+  Fts5Index *p, 
+  Fts5SegWriter *pWriter,
+  int bFlush                      /* If true, write dlidx to disk */
+){
+  int i;
+  assert( bFlush==0 || (pWriter->nDlidx>0 && pWriter->aDlidx[0].buf.n>0) );
+  for(i=0; i<pWriter->nDlidx; i++){
+    Fts5DlidxWriter *pDlidx = &pWriter->aDlidx[i];
+    if( pDlidx->buf.n==0 ) break;
+    if( bFlush ){
+      assert( pDlidx->pgno!=0 );
+      fts5DataWrite(p, 
+          FTS5_DLIDX_ROWID(pWriter->iSegid, i, pDlidx->pgno),
+          pDlidx->buf.p, pDlidx->buf.n
+      );
+    }
+    sqlite3Fts5BufferZero(&pDlidx->buf);
+    pDlidx->bPrevValid = 0;
+  }
+}
+
+/*
+** Grow the pWriter->aDlidx[] array to at least nLvl elements in size.
+** Any new array elements are zeroed before returning.
+*/
+static int fts5WriteDlidxGrow(
+  Fts5Index *p,
+  Fts5SegWriter *pWriter,
+  int nLvl
+){
+  if( p->rc==SQLITE_OK && nLvl>=pWriter->nDlidx ){
+    Fts5DlidxWriter *aDlidx = (Fts5DlidxWriter*)sqlite3_realloc(
+        pWriter->aDlidx, sizeof(Fts5DlidxWriter) * nLvl
+    );
+    if( aDlidx==0 ){
+      p->rc = SQLITE_NOMEM;
+    }else{
+      int nByte = sizeof(Fts5DlidxWriter) * (nLvl - pWriter->nDlidx);
+      memset(&aDlidx[pWriter->nDlidx], 0, nByte);
+      pWriter->aDlidx = aDlidx;
+      pWriter->nDlidx = nLvl;
+    }
+  }
+  return p->rc;
+}
+
+/*
+** If the current doclist-index accumulating in pWriter->aDlidx[] is large
+** enough, flush it to disk and return 1. Otherwise discard it and return
+** zero.
+*/
+static int fts5WriteFlushDlidx(Fts5Index *p, Fts5SegWriter *pWriter){
+  int bFlag = 0;
+
+  /* If there were FTS5_MIN_DLIDX_SIZE or more empty leaf pages written
+  ** to the database, also write the doclist-index to disk.  */
+  if( pWriter->aDlidx[0].buf.n>0 && pWriter->nEmpty>=FTS5_MIN_DLIDX_SIZE ){
+    bFlag = 1;
+  }
+  fts5WriteDlidxClear(p, pWriter, bFlag);
+  pWriter->nEmpty = 0;
+  return bFlag;
+}
+
+/*
+** This function is called whenever processing of the doclist for the 
+** last term on leaf page (pWriter->iBtPage) is completed. 
+**
+** The doclist-index for that term is currently stored in-memory within the
+** Fts5SegWriter.aDlidx[] array. If it is large enough, this function
+** writes it out to disk. Or, if it is too small to bother with, discards
+** it.
+**
+** Fts5SegWriter.btterm currently contains the first term on page iBtPage.
+*/
+static void fts5WriteFlushBtree(Fts5Index *p, Fts5SegWriter *pWriter){
+  int bFlag;
+
+  assert( pWriter->iBtPage || pWriter->nEmpty==0 );
+  if( pWriter->iBtPage==0 ) return;
+  bFlag = fts5WriteFlushDlidx(p, pWriter);
+
+  if( p->rc==SQLITE_OK ){
+    const char *z = (pWriter->btterm.n>0?(const char*)pWriter->btterm.p:"");
+    /* The following was already done in fts5WriteInit(): */
+    /* sqlite3_bind_int(p->pIdxWriter, 1, pWriter->iSegid); */
+    sqlite3_bind_blob(p->pIdxWriter, 2, z, pWriter->btterm.n, SQLITE_STATIC);
+    sqlite3_bind_int64(p->pIdxWriter, 3, bFlag + ((i64)pWriter->iBtPage<<1));
+    sqlite3_step(p->pIdxWriter);
+    p->rc = sqlite3_reset(p->pIdxWriter);
+  }
+  pWriter->iBtPage = 0;
+}
+
+/*
+** This is called once for each leaf page except the first that contains
+** at least one term. Argument (nTerm/pTerm) is the split-key - a term that
+** is larger than all terms written to earlier leaves, and equal to or
+** smaller than the first term on the new leaf.
+**
+** If an error occurs, an error code is left in Fts5Index.rc. If an error
+** has already occurred when this function is called, it is a no-op.
+*/
+static void fts5WriteBtreeTerm(
+  Fts5Index *p,                   /* FTS5 backend object */
+  Fts5SegWriter *pWriter,         /* Writer object */
+  int nTerm, const u8 *pTerm      /* First term on new page */
+){
+  fts5WriteFlushBtree(p, pWriter);
+  fts5BufferSet(&p->rc, &pWriter->btterm, nTerm, pTerm);
+  pWriter->iBtPage = pWriter->writer.pgno;
+}
+
+/*
+** This function is called when flushing a leaf page that contains no
+** terms at all to disk.
+*/
+static void fts5WriteBtreeNoTerm(
+  Fts5Index *p,                   /* FTS5 backend object */
+  Fts5SegWriter *pWriter          /* Writer object */
+){
+  /* If there were no rowids on the leaf page either and the doclist-index
+  ** has already been started, append an 0x00 byte to it.  */
+  if( pWriter->bFirstRowidInPage && pWriter->aDlidx[0].buf.n>0 ){
+    Fts5DlidxWriter *pDlidx = &pWriter->aDlidx[0];
+    assert( pDlidx->bPrevValid );
+    sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx->buf, 0);
+  }
+
+  /* Increment the "number of sequential leaves without a term" counter. */
+  pWriter->nEmpty++;
+}
+
+static i64 fts5DlidxExtractFirstRowid(Fts5Buffer *pBuf){
+  i64 iRowid;
+  int iOff;
+
+  iOff = 1 + fts5GetVarint(&pBuf->p[1], (u64*)&iRowid);
+  fts5GetVarint(&pBuf->p[iOff], (u64*)&iRowid);
+  return iRowid;
+}
+
+/*
+** Rowid iRowid has just been appended to the current leaf page. It is the
+** first on the page. This function appends an appropriate entry to the current
+** doclist-index.
+*/
+static void fts5WriteDlidxAppend(
+  Fts5Index *p, 
+  Fts5SegWriter *pWriter, 
+  i64 iRowid
+){
+  int i;
+  int bDone = 0;
+
+  for(i=0; p->rc==SQLITE_OK && bDone==0; i++){
+    i64 iVal;
+    Fts5DlidxWriter *pDlidx = &pWriter->aDlidx[i];
+
+    if( pDlidx->buf.n>=p->pConfig->pgsz ){
+      /* The current doclist-index page is full. Write it to disk and push
+      ** a copy of iRowid (which will become the first rowid on the next
+      ** doclist-index leaf page) up into the next level of the b-tree 
+      ** hierarchy. If the node being flushed is currently the root node,
+      ** also push its first rowid upwards. */
+      pDlidx->buf.p[0] = 0x01;    /* Not the root node */
+      fts5DataWrite(p, 
+          FTS5_DLIDX_ROWID(pWriter->iSegid, i, pDlidx->pgno),
+          pDlidx->buf.p, pDlidx->buf.n
+      );
+      fts5WriteDlidxGrow(p, pWriter, i+2);
+      pDlidx = &pWriter->aDlidx[i];
+      if( p->rc==SQLITE_OK && pDlidx[1].buf.n==0 ){
+        i64 iFirst = fts5DlidxExtractFirstRowid(&pDlidx->buf);
+
+        /* This was the root node. Push its first rowid up to the new root. */
+        pDlidx[1].pgno = pDlidx->pgno;
+        sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx[1].buf, 0);
+        sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx[1].buf, pDlidx->pgno);
+        sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx[1].buf, iFirst);
+        pDlidx[1].bPrevValid = 1;
+        pDlidx[1].iPrev = iFirst;
+      }
+
+      sqlite3Fts5BufferZero(&pDlidx->buf);
+      pDlidx->bPrevValid = 0;
+      pDlidx->pgno++;
+    }else{
+      bDone = 1;
+    }
+
+    if( pDlidx->bPrevValid ){
+      iVal = iRowid - pDlidx->iPrev;
+    }else{
+      i64 iPgno = (i==0 ? pWriter->writer.pgno : pDlidx[-1].pgno);
+      assert( pDlidx->buf.n==0 );
+      sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx->buf, !bDone);
+      sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx->buf, iPgno);
+      iVal = iRowid;
+    }
+
+    sqlite3Fts5BufferAppendVarint(&p->rc, &pDlidx->buf, iVal);
+    pDlidx->bPrevValid = 1;
+    pDlidx->iPrev = iRowid;
+  }
+}
+
+static void fts5WriteFlushLeaf(Fts5Index *p, Fts5SegWriter *pWriter){
+  static const u8 zero[] = { 0x00, 0x00, 0x00, 0x00 };
+  Fts5PageWriter *pPage = &pWriter->writer;
+  i64 iRowid;
+
+  assert( (pPage->pgidx.n==0)==(pWriter->bFirstTermInPage) );
+
+  /* Set the szLeaf header field. */
+  assert( 0==fts5GetU16(&pPage->buf.p[2]) );
+  fts5PutU16(&pPage->buf.p[2], pPage->buf.n);
+
+  if( pWriter->bFirstTermInPage ){
+    /* No term was written to this page. */
+    assert( pPage->pgidx.n==0 );
+    fts5WriteBtreeNoTerm(p, pWriter);
+  }else{
+    /* Append the pgidx to the page buffer. Set the szLeaf header field. */
+    fts5BufferAppendBlob(&p->rc, &pPage->buf, pPage->pgidx.n, pPage->pgidx.p);
+  }
+
+  /* Write the page out to disk */
+  iRowid = FTS5_SEGMENT_ROWID(pWriter->iSegid, pPage->pgno);
+  fts5DataWrite(p, iRowid, pPage->buf.p, pPage->buf.n);
+
+  /* Initialize the next page. */
+  fts5BufferZero(&pPage->buf);
+  fts5BufferZero(&pPage->pgidx);
+  fts5BufferAppendBlob(&p->rc, &pPage->buf, 4, zero);
+  pPage->iPrevPgidx = 0;
+  pPage->pgno++;
+
+  /* Increase the leaves written counter */
+  pWriter->nLeafWritten++;
+
+  /* The new leaf holds no terms or rowids */
+  pWriter->bFirstTermInPage = 1;
+  pWriter->bFirstRowidInPage = 1;
+}
+
+/*
+** Append term pTerm/nTerm to the segment being written by the writer passed
+** as the second argument.
+**
+** If an error occurs, set the Fts5Index.rc error code. If an error has 
+** already occurred, this function is a no-op.
+*/
+static void fts5WriteAppendTerm(
+  Fts5Index *p, 
+  Fts5SegWriter *pWriter,
+  int nTerm, const u8 *pTerm 
+){
+  int nPrefix;                    /* Bytes of prefix compression for term */
+  Fts5PageWriter *pPage = &pWriter->writer;
+  Fts5Buffer *pPgidx = &pWriter->writer.pgidx;
+
+  assert( p->rc==SQLITE_OK );
+  assert( pPage->buf.n>=4 );
+  assert( pPage->buf.n>4 || pWriter->bFirstTermInPage );
+
+  /* If the current leaf page is full, flush it to disk. */
+  if( (pPage->buf.n + pPgidx->n + nTerm + 2)>=p->pConfig->pgsz ){
+    if( pPage->buf.n>4 ){
+      fts5WriteFlushLeaf(p, pWriter);
+    }
+    fts5BufferGrow(&p->rc, &pPage->buf, nTerm+FTS5_DATA_PADDING);
+  }
+  
+  /* TODO1: Updating pgidx here. */
+  pPgidx->n += sqlite3Fts5PutVarint(
+      &pPgidx->p[pPgidx->n], pPage->buf.n - pPage->iPrevPgidx
+  );
+  pPage->iPrevPgidx = pPage->buf.n;
+#if 0
+  fts5PutU16(&pPgidx->p[pPgidx->n], pPage->buf.n);
+  pPgidx->n += 2;
+#endif
+
+  if( pWriter->bFirstTermInPage ){
+    nPrefix = 0;
+    if( pPage->pgno!=1 ){
+      /* This is the first term on a leaf that is not the leftmost leaf in
+      ** the segment b-tree. In this case it is necessary to add a term to
+      ** the b-tree hierarchy that is (a) larger than the largest term 
+      ** already written to the segment and (b) smaller than or equal to
+      ** this term. In other words, a prefix of (pTerm/nTerm) that is one
+      ** byte longer than the longest prefix (pTerm/nTerm) shares with the
+      ** previous term. 
+      **
+      ** Usually, the previous term is available in pPage->term. The exception
+      ** is if this is the first term written in an incremental-merge step.
+      ** In this case the previous term is not available, so just write a
+      ** copy of (pTerm/nTerm) into the parent node. This is slightly
+      ** inefficient, but still correct.  */
+      int n = nTerm;
+      if( pPage->term.n ){
+        n = 1 + fts5PrefixCompress(pPage->term.n, pPage->term.p, nTerm, pTerm);
+      }
+      fts5WriteBtreeTerm(p, pWriter, n, pTerm);
+      pPage = &pWriter->writer;
+    }
+  }else{
+    nPrefix = fts5PrefixCompress(pPage->term.n, pPage->term.p, nTerm, pTerm);
+    fts5BufferAppendVarint(&p->rc, &pPage->buf, nPrefix);
+  }
+
+  /* Append the number of bytes of new data, then the term data itself
+  ** to the page. */
+  fts5BufferAppendVarint(&p->rc, &pPage->buf, nTerm - nPrefix);
+  fts5BufferAppendBlob(&p->rc, &pPage->buf, nTerm - nPrefix, &pTerm[nPrefix]);
+
+  /* Update the Fts5PageWriter.term field. */
+  fts5BufferSet(&p->rc, &pPage->term, nTerm, pTerm);
+  pWriter->bFirstTermInPage = 0;
+
+  pWriter->bFirstRowidInPage = 0;
+  pWriter->bFirstRowidInDoclist = 1;
+
+  assert( p->rc || (pWriter->nDlidx>0 && pWriter->aDlidx[0].buf.n==0) );
+  pWriter->aDlidx[0].pgno = pPage->pgno;
+}
+
+/*
+** Append a rowid and position-list size field to the writers output. 
+*/
+static void fts5WriteAppendRowid(
+  Fts5Index *p, 
+  Fts5SegWriter *pWriter,
+  i64 iRowid,
+  int nPos
+){
+  if( p->rc==SQLITE_OK ){
+    Fts5PageWriter *pPage = &pWriter->writer;
+
+    if( (pPage->buf.n + pPage->pgidx.n)>=p->pConfig->pgsz ){
+      fts5WriteFlushLeaf(p, pWriter);
+    }
+
+    /* If this is to be the first rowid written to the page, set the 
+    ** rowid-pointer in the page-header. Also append a value to the dlidx
+    ** buffer, in case a doclist-index is required.  */
+    if( pWriter->bFirstRowidInPage ){
+      fts5PutU16(pPage->buf.p, pPage->buf.n);
+      fts5WriteDlidxAppend(p, pWriter, iRowid);
+    }
+
+    /* Write the rowid. */
+    if( pWriter->bFirstRowidInDoclist || pWriter->bFirstRowidInPage ){
+      fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid);
+    }else{
+      assert( p->rc || iRowid>pWriter->iPrevRowid );
+      fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid - pWriter->iPrevRowid);
+    }
+    pWriter->iPrevRowid = iRowid;
+    pWriter->bFirstRowidInDoclist = 0;
+    pWriter->bFirstRowidInPage = 0;
+
+    fts5BufferAppendVarint(&p->rc, &pPage->buf, nPos);
+  }
+}
+
+static void fts5WriteAppendPoslistData(
+  Fts5Index *p, 
+  Fts5SegWriter *pWriter, 
+  const u8 *aData, 
+  int nData
+){
+  Fts5PageWriter *pPage = &pWriter->writer;
+  const u8 *a = aData;
+  int n = nData;
+  
+  assert( p->pConfig->pgsz>0 );
+  while( p->rc==SQLITE_OK 
+     && (pPage->buf.n + pPage->pgidx.n + n)>=p->pConfig->pgsz 
+  ){
+    int nReq = p->pConfig->pgsz - pPage->buf.n - pPage->pgidx.n;
+    int nCopy = 0;
+    while( nCopy<nReq ){
+      i64 dummy;
+      nCopy += fts5GetVarint(&a[nCopy], (u64*)&dummy);
+    }
+    fts5BufferAppendBlob(&p->rc, &pPage->buf, nCopy, a);
+    a += nCopy;
+    n -= nCopy;
+    fts5WriteFlushLeaf(p, pWriter);
+  }
+  if( n>0 ){
+    fts5BufferAppendBlob(&p->rc, &pPage->buf, n, a);
+  }
+}
+
+/*
+** Flush any data cached by the writer object to the database. Free any
+** allocations associated with the writer.
+*/
+static void fts5WriteFinish(
+  Fts5Index *p, 
+  Fts5SegWriter *pWriter,         /* Writer object */
+  int *pnLeaf                     /* OUT: Number of leaf pages in b-tree */
+){
+  int i;
+  Fts5PageWriter *pLeaf = &pWriter->writer;
+  if( p->rc==SQLITE_OK ){
+    assert( pLeaf->pgno>=1 );
+    if( pLeaf->buf.n>4 ){
+      fts5WriteFlushLeaf(p, pWriter);
+    }
+    *pnLeaf = pLeaf->pgno-1;
+    fts5WriteFlushBtree(p, pWriter);
+  }
+  fts5BufferFree(&pLeaf->term);
+  fts5BufferFree(&pLeaf->buf);
+  fts5BufferFree(&pLeaf->pgidx);
+  fts5BufferFree(&pWriter->btterm);
+
+  for(i=0; i<pWriter->nDlidx; i++){
+    sqlite3Fts5BufferFree(&pWriter->aDlidx[i].buf);
+  }
+  sqlite3_free(pWriter->aDlidx);
+}
+
+static void fts5WriteInit(
+  Fts5Index *p, 
+  Fts5SegWriter *pWriter, 
+  int iSegid
+){
+  const int nBuffer = p->pConfig->pgsz + FTS5_DATA_PADDING;
+
+  memset(pWriter, 0, sizeof(Fts5SegWriter));
+  pWriter->iSegid = iSegid;
+
+  fts5WriteDlidxGrow(p, pWriter, 1);
+  pWriter->writer.pgno = 1;
+  pWriter->bFirstTermInPage = 1;
+  pWriter->iBtPage = 1;
+
+  /* Grow the two buffers to pgsz + padding bytes in size. */
+  fts5BufferGrow(&p->rc, &pWriter->writer.pgidx, nBuffer);
+  fts5BufferGrow(&p->rc, &pWriter->writer.buf, nBuffer);
+
+  if( p->pIdxWriter==0 ){
+    Fts5Config *pConfig = p->pConfig;
+    fts5IndexPrepareStmt(p, &p->pIdxWriter, sqlite3_mprintf(
+          "INSERT INTO '%q'.'%q_idx'(segid,term,pgno) VALUES(?,?,?)", 
+          pConfig->zDb, pConfig->zName
+    ));
+  }
+
+  if( p->rc==SQLITE_OK ){
+    /* Initialize the 4-byte leaf-page header to 0x00. */
+    memset(pWriter->writer.buf.p, 0, 4);
+    pWriter->writer.buf.n = 4;
+
+    /* Bind the current output segment id to the index-writer. This is an
+    ** optimization over binding the same value over and over as rows are
+    ** inserted into %_idx by the current writer.  */
+    sqlite3_bind_int(p->pIdxWriter, 1, pWriter->iSegid);
+  }
+}
+
+/*
+** Iterator pIter was used to iterate through the input segments of on an
+** incremental merge operation. This function is called if the incremental
+** merge step has finished but the input has not been completely exhausted.
+*/
+static void fts5TrimSegments(Fts5Index *p, Fts5IndexIter *pIter){
+  int i;
+  Fts5Buffer buf;
+  memset(&buf, 0, sizeof(Fts5Buffer));
+  for(i=0; i<pIter->nSeg; i++){
+    Fts5SegIter *pSeg = &pIter->aSeg[i];
+    if( pSeg->pSeg==0 ){
+      /* no-op */
+    }else if( pSeg->pLeaf==0 ){
+      /* All keys from this input segment have been transfered to the output.
+      ** Set both the first and last page-numbers to 0 to indicate that the
+      ** segment is now empty. */
+      pSeg->pSeg->pgnoLast = 0;
+      pSeg->pSeg->pgnoFirst = 0;
+    }else{
+      int iOff = pSeg->iTermLeafOffset;     /* Offset on new first leaf page */
+      i64 iLeafRowid;
+      Fts5Data *pData;
+      int iId = pSeg->pSeg->iSegid;
+      u8 aHdr[4] = {0x00, 0x00, 0x00, 0x00};
+
+      iLeafRowid = FTS5_SEGMENT_ROWID(iId, pSeg->iTermLeafPgno);
+      pData = fts5DataRead(p, iLeafRowid);
+      if( pData ){
+        fts5BufferZero(&buf);
+        fts5BufferGrow(&p->rc, &buf, pData->nn);
+        fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr);
+        fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n);
+        fts5BufferAppendBlob(&p->rc, &buf, pSeg->term.n, pSeg->term.p);
+        fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff, &pData->p[iOff]);
+        if( p->rc==SQLITE_OK ){
+          /* Set the szLeaf field */
+          fts5PutU16(&buf.p[2], buf.n);
+        }
+
+        /* Set up the new page-index array */
+        fts5BufferAppendVarint(&p->rc, &buf, 4);
+        if( pSeg->iLeafPgno==pSeg->iTermLeafPgno 
+         && pSeg->iEndofDoclist<pData->szLeaf 
+        ){
+          int nDiff = pData->szLeaf - pSeg->iEndofDoclist;
+          fts5BufferAppendVarint(&p->rc, &buf, buf.n - 1 - nDiff - 4);
+          fts5BufferAppendBlob(&p->rc, &buf, 
+              pData->nn - pSeg->iPgidxOff, &pData->p[pSeg->iPgidxOff]
+          );
+        }
+
+        fts5DataRelease(pData);
+        pSeg->pSeg->pgnoFirst = pSeg->iTermLeafPgno;
+        fts5DataDelete(p, FTS5_SEGMENT_ROWID(iId, 1), iLeafRowid);
+        fts5DataWrite(p, iLeafRowid, buf.p, buf.n);
+      }
+    }
+  }
+  fts5BufferFree(&buf);
+}
+
+static void fts5MergeChunkCallback(
+  Fts5Index *p, 
+  void *pCtx, 
+  const u8 *pChunk, int nChunk
+){
+  Fts5SegWriter *pWriter = (Fts5SegWriter*)pCtx;
+  fts5WriteAppendPoslistData(p, pWriter, pChunk, nChunk);
+}
+
+/*
+**
+*/
+static void fts5IndexMergeLevel(
+  Fts5Index *p,                   /* FTS5 backend object */
+  Fts5Structure **ppStruct,       /* IN/OUT: Stucture of index */
+  int iLvl,                       /* Level to read input from */
+  int *pnRem                      /* Write up to this many output leaves */
+){
+  Fts5Structure *pStruct = *ppStruct;
+  Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
+  Fts5StructureLevel *pLvlOut;
+  Fts5IndexIter *pIter = 0;       /* Iterator to read input data */
+  int nRem = pnRem ? *pnRem : 0;  /* Output leaf pages left to write */
+  int nInput;                     /* Number of input segments */
+  Fts5SegWriter writer;           /* Writer object */
+  Fts5StructureSegment *pSeg;     /* Output segment */
+  Fts5Buffer term;
+  int bOldest;                    /* True if the output segment is the oldest */
+
+  assert( iLvl<pStruct->nLevel );
+  assert( pLvl->nMerge<=pLvl->nSeg );
+
+  memset(&writer, 0, sizeof(Fts5SegWriter));
+  memset(&term, 0, sizeof(Fts5Buffer));
+  if( pLvl->nMerge ){
+    pLvlOut = &pStruct->aLevel[iLvl+1];
+    assert( pLvlOut->nSeg>0 );
+    nInput = pLvl->nMerge;
+    pSeg = &pLvlOut->aSeg[pLvlOut->nSeg-1];
+
+    fts5WriteInit(p, &writer, pSeg->iSegid);
+    writer.writer.pgno = pSeg->pgnoLast+1;
+    writer.iBtPage = 0;
+  }else{
+    int iSegid = fts5AllocateSegid(p, pStruct);
+
+    /* Extend the Fts5Structure object as required to ensure the output
+    ** segment exists. */
+    if( iLvl==pStruct->nLevel-1 ){
+      fts5StructureAddLevel(&p->rc, ppStruct);
+      pStruct = *ppStruct;
+    }
+    fts5StructureExtendLevel(&p->rc, pStruct, iLvl+1, 1, 0);
+    if( p->rc ) return;
+    pLvl = &pStruct->aLevel[iLvl];
+    pLvlOut = &pStruct->aLevel[iLvl+1];
+
+    fts5WriteInit(p, &writer, iSegid);
+
+    /* Add the new segment to the output level */
+    pSeg = &pLvlOut->aSeg[pLvlOut->nSeg];
+    pLvlOut->nSeg++;
+    pSeg->pgnoFirst = 1;
+    pSeg->iSegid = iSegid;
+    pStruct->nSegment++;
+
+    /* Read input from all segments in the input level */
+    nInput = pLvl->nSeg;
+  }
+  bOldest = (pLvlOut->nSeg==1 && pStruct->nLevel==iLvl+2);
+
+  assert( iLvl>=0 );
+  for(fts5MultiIterNew(p, pStruct, 0, 0, 0, 0, iLvl, nInput, &pIter);
+      fts5MultiIterEof(p, pIter)==0;
+      fts5MultiIterNext(p, pIter, 0, 0)
+  ){
+    Fts5SegIter *pSegIter = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
+    int nPos;                     /* position-list size field value */
+    int nTerm;
+    const u8 *pTerm;
+
+    /* Check for key annihilation. */
+    if( pSegIter->nPos==0 && (bOldest || pSegIter->bDel==0) ) continue;
+
+    pTerm = fts5MultiIterTerm(pIter, &nTerm);
+    if( nTerm!=term.n || memcmp(pTerm, term.p, nTerm) ){
+      if( pnRem && writer.nLeafWritten>nRem ){
+        break;
+      }
+
+      /* This is a new term. Append a term to the output segment. */
+      fts5WriteAppendTerm(p, &writer, nTerm, pTerm);
+      fts5BufferSet(&p->rc, &term, nTerm, pTerm);
+    }
+
+    /* Append the rowid to the output */
+    /* WRITEPOSLISTSIZE */
+    nPos = pSegIter->nPos*2 + pSegIter->bDel;
+    fts5WriteAppendRowid(p, &writer, fts5MultiIterRowid(pIter), nPos);
+
+    /* Append the position-list data to the output */
+    fts5ChunkIterate(p, pSegIter, (void*)&writer, fts5MergeChunkCallback);
+  }
+
+  /* Flush the last leaf page to disk. Set the output segment b-tree height
+  ** and last leaf page number at the same time.  */
+  fts5WriteFinish(p, &writer, &pSeg->pgnoLast);
+
+  if( fts5MultiIterEof(p, pIter) ){
+    int i;
+
+    /* Remove the redundant segments from the %_data table */
+    for(i=0; i<nInput; i++){
+      fts5DataRemoveSegment(p, pLvl->aSeg[i].iSegid);
+    }
+
+    /* Remove the redundant segments from the input level */
+    if( pLvl->nSeg!=nInput ){
+      int nMove = (pLvl->nSeg - nInput) * sizeof(Fts5StructureSegment);
+      memmove(pLvl->aSeg, &pLvl->aSeg[nInput], nMove);
+    }
+    pStruct->nSegment -= nInput;
+    pLvl->nSeg -= nInput;
+    pLvl->nMerge = 0;
+    if( pSeg->pgnoLast==0 ){
+      pLvlOut->nSeg--;
+      pStruct->nSegment--;
+    }
+  }else{
+    assert( pSeg->pgnoLast>0 );
+    fts5TrimSegments(p, pIter);
+    pLvl->nMerge = nInput;
+  }
+
+  fts5MultiIterFree(p, pIter);
+  fts5BufferFree(&term);
+  if( pnRem ) *pnRem -= writer.nLeafWritten;
+}
+
+/*
+** Do up to nPg pages of automerge work on the index.
+*/
+static void fts5IndexMerge(
+  Fts5Index *p,                   /* FTS5 backend object */
+  Fts5Structure **ppStruct,       /* IN/OUT: Current structure of index */
+  int nPg                         /* Pages of work to do */
+){
+  int nRem = nPg;
+  Fts5Structure *pStruct = *ppStruct;
+  while( nRem>0 && p->rc==SQLITE_OK ){
+    int iLvl;                   /* To iterate through levels */
+    int iBestLvl = 0;           /* Level offering the most input segments */
+    int nBest = 0;              /* Number of input segments on best level */
+
+    /* Set iBestLvl to the level to read input segments from. */
+    assert( pStruct->nLevel>0 );
+    for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
+      Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
+      if( pLvl->nMerge ){
+        if( pLvl->nMerge>nBest ){
+          iBestLvl = iLvl;
+          nBest = pLvl->nMerge;
+        }
+        break;
+      }
+      if( pLvl->nSeg>nBest ){
+        nBest = pLvl->nSeg;
+        iBestLvl = iLvl;
+      }
+    }
+
+    /* If nBest is still 0, then the index must be empty. */
+#ifdef SQLITE_DEBUG
+    for(iLvl=0; nBest==0 && iLvl<pStruct->nLevel; iLvl++){
+      assert( pStruct->aLevel[iLvl].nSeg==0 );
+    }
+#endif
+
+    if( nBest<p->pConfig->nAutomerge 
+        && pStruct->aLevel[iBestLvl].nMerge==0 
+      ){
+      break;
+    }
+    fts5IndexMergeLevel(p, &pStruct, iBestLvl, &nRem);
+    if( p->rc==SQLITE_OK && pStruct->aLevel[iBestLvl].nMerge==0 ){
+      fts5StructurePromote(p, iBestLvl+1, pStruct);
+    }
+  }
+  *ppStruct = pStruct;
+}
+
+/*
+** A total of nLeaf leaf pages of data has just been flushed to a level-0
+** segment. This function updates the write-counter accordingly and, if
+** necessary, performs incremental merge work.
+**
+** If an error occurs, set the Fts5Index.rc error code. If an error has 
+** already occurred, this function is a no-op.
+*/
+static void fts5IndexAutomerge(
+  Fts5Index *p,                   /* FTS5 backend object */
+  Fts5Structure **ppStruct,       /* IN/OUT: Current structure of index */
+  int nLeaf                       /* Number of output leaves just written */
+){
+  if( p->rc==SQLITE_OK && p->pConfig->nAutomerge>0 ){
+    Fts5Structure *pStruct = *ppStruct;
+    u64 nWrite;                   /* Initial value of write-counter */
+    int nWork;                    /* Number of work-quanta to perform */
+    int nRem;                     /* Number of leaf pages left to write */
+
+    /* Update the write-counter. While doing so, set nWork. */
+    nWrite = pStruct->nWriteCounter;
+    nWork = (int)(((nWrite + nLeaf) / p->nWorkUnit) - (nWrite / p->nWorkUnit));
+    pStruct->nWriteCounter += nLeaf;
+    nRem = (int)(p->nWorkUnit * nWork * pStruct->nLevel);
+
+    fts5IndexMerge(p, ppStruct, nRem);
+  }
+}
+
+static void fts5IndexCrisismerge(
+  Fts5Index *p,                   /* FTS5 backend object */
+  Fts5Structure **ppStruct        /* IN/OUT: Current structure of index */
+){
+  const int nCrisis = p->pConfig->nCrisisMerge;
+  Fts5Structure *pStruct = *ppStruct;
+  int iLvl = 0;
+
+  assert( p->rc!=SQLITE_OK || pStruct->nLevel>0 );
+  while( p->rc==SQLITE_OK && pStruct->aLevel[iLvl].nSeg>=nCrisis ){
+    fts5IndexMergeLevel(p, &pStruct, iLvl, 0);
+    assert( p->rc!=SQLITE_OK || pStruct->nLevel>(iLvl+1) );
+    fts5StructurePromote(p, iLvl+1, pStruct);
+    iLvl++;
+  }
+  *ppStruct = pStruct;
+}
+
+static int fts5IndexReturn(Fts5Index *p){
+  int rc = p->rc;
+  p->rc = SQLITE_OK;
+  return rc;
+}
+
+typedef struct Fts5FlushCtx Fts5FlushCtx;
+struct Fts5FlushCtx {
+  Fts5Index *pIdx;
+  Fts5SegWriter writer; 
+};
+
+/*
+** Buffer aBuf[] contains a list of varints, all small enough to fit
+** in a 32-bit integer. Return the size of the largest prefix of this 
+** list nMax bytes or less in size.
+*/
+static int fts5PoslistPrefix(const u8 *aBuf, int nMax){
+  int ret;
+  u32 dummy;
+  ret = fts5GetVarint32(aBuf, dummy);
+  if( ret<nMax ){
+    while( 1 ){
+      int i = fts5GetVarint32(&aBuf[ret], dummy);
+      if( (ret + i) > nMax ) break;
+      ret += i;
+    }
+  }
+  return ret;
+}
+
+#define fts5BufferSafeAppendBlob(pBuf, pBlob, nBlob) {     \
+  assert( (pBuf)->nSpace>=((pBuf)->n+nBlob) );             \
+  memcpy(&(pBuf)->p[(pBuf)->n], pBlob, nBlob);             \
+  (pBuf)->n += nBlob;                                      \
+}
+
+#define fts5BufferSafeAppendVarint(pBuf, iVal) {                \
+  (pBuf)->n += sqlite3Fts5PutVarint(&(pBuf)->p[(pBuf)->n], (iVal));  \
+  assert( (pBuf)->nSpace>=(pBuf)->n );                          \
+}
+
+/*
+** Flush the contents of in-memory hash table iHash to a new level-0 
+** segment on disk. Also update the corresponding structure record.
+**
+** If an error occurs, set the Fts5Index.rc error code. If an error has 
+** already occurred, this function is a no-op.
+*/
+static void fts5FlushOneHash(Fts5Index *p){
+  Fts5Hash *pHash = p->pHash;
+  Fts5Structure *pStruct;
+  int iSegid;
+  int pgnoLast = 0;                 /* Last leaf page number in segment */
+
+  /* Obtain a reference to the index structure and allocate a new segment-id
+  ** for the new level-0 segment.  */
+  pStruct = fts5StructureRead(p);
+  iSegid = fts5AllocateSegid(p, pStruct);
+
+  if( iSegid ){
+    const int pgsz = p->pConfig->pgsz;
+
+    Fts5StructureSegment *pSeg;   /* New segment within pStruct */
+    Fts5Buffer *pBuf;             /* Buffer in which to assemble leaf page */
+    Fts5Buffer *pPgidx;           /* Buffer in which to assemble pgidx */
+
+    Fts5SegWriter writer;
+    fts5WriteInit(p, &writer, iSegid);
+
+    pBuf = &writer.writer.buf;
+    pPgidx = &writer.writer.pgidx;
+
+    /* fts5WriteInit() should have initialized the buffers to (most likely)
+    ** the maximum space required. */
+    assert( p->rc || pBuf->nSpace>=(pgsz + FTS5_DATA_PADDING) );
+    assert( p->rc || pPgidx->nSpace>=(pgsz + FTS5_DATA_PADDING) );
+
+    /* Begin scanning through hash table entries. This loop runs once for each
+    ** term/doclist currently stored within the hash table. */
+    if( p->rc==SQLITE_OK ){
+      p->rc = sqlite3Fts5HashScanInit(pHash, 0, 0);
+    }
+    while( p->rc==SQLITE_OK && 0==sqlite3Fts5HashScanEof(pHash) ){
+      const char *zTerm;          /* Buffer containing term */
+      const u8 *pDoclist;         /* Pointer to doclist for this term */
+      int nDoclist;               /* Size of doclist in bytes */
+
+      /* Write the term for this entry to disk. */
+      sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist);
+      fts5WriteAppendTerm(p, &writer, strlen(zTerm), (const u8*)zTerm);
+
+      assert( writer.bFirstRowidInPage==0 );
+      if( pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){
+        /* The entire doclist will fit on the current leaf. */
+        fts5BufferSafeAppendBlob(pBuf, pDoclist, nDoclist);
+      }else{
+        i64 iRowid = 0;
+        i64 iDelta = 0;
+        int iOff = 0;
+
+        /* The entire doclist will not fit on this leaf. The following 
+        ** loop iterates through the poslists that make up the current 
+        ** doclist.  */
+        while( p->rc==SQLITE_OK && iOff<nDoclist ){
+          int nPos;
+          int nCopy;
+          int bDummy;
+          iOff += fts5GetVarint(&pDoclist[iOff], (u64*)&iDelta);
+          nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDummy);
+          nCopy += nPos;
+          iRowid += iDelta;
+          
+          if( writer.bFirstRowidInPage ){
+            fts5PutU16(&pBuf->p[0], pBuf->n);   /* first rowid on page */
+            pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid);
+            writer.bFirstRowidInPage = 0;
+            fts5WriteDlidxAppend(p, &writer, iRowid);
+          }else{
+            pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iDelta);
+          }
+          assert( pBuf->n<=pBuf->nSpace );
+
+          if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){
+            /* The entire poslist will fit on the current leaf. So copy
+            ** it in one go. */
+            fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy);
+          }else{
+            /* The entire poslist will not fit on this leaf. So it needs
+            ** to be broken into sections. The only qualification being
+            ** that each varint must be stored contiguously.  */
+            const u8 *pPoslist = &pDoclist[iOff];
+            int iPos = 0;
+            while( p->rc==SQLITE_OK ){
+              int nSpace = pgsz - pBuf->n - pPgidx->n;
+              int n = 0;
+              if( (nCopy - iPos)<=nSpace ){
+                n = nCopy - iPos;
+              }else{
+                n = fts5PoslistPrefix(&pPoslist[iPos], nSpace);
+              }
+              assert( n>0 );
+              fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n);
+              iPos += n;
+              if( (pBuf->n + pPgidx->n)>=pgsz ){
+                fts5WriteFlushLeaf(p, &writer);
+              }
+              if( iPos>=nCopy ) break;
+            }
+          }
+          iOff += nCopy;
+        }
+      }
+
+      /* TODO2: Doclist terminator written here. */
+      /* pBuf->p[pBuf->n++] = '\0'; */
+      assert( pBuf->n<=pBuf->nSpace );
+      sqlite3Fts5HashScanNext(pHash);
+    }
+    sqlite3Fts5HashClear(pHash);
+    fts5WriteFinish(p, &writer, &pgnoLast);
+
+    /* Update the Fts5Structure. It is written back to the database by the
+    ** fts5StructureRelease() call below.  */
+    if( pStruct->nLevel==0 ){
+      fts5StructureAddLevel(&p->rc, &pStruct);
+    }
+    fts5StructureExtendLevel(&p->rc, pStruct, 0, 1, 0);
+    if( p->rc==SQLITE_OK ){
+      pSeg = &pStruct->aLevel[0].aSeg[ pStruct->aLevel[0].nSeg++ ];
+      pSeg->iSegid = iSegid;
+      pSeg->pgnoFirst = 1;
+      pSeg->pgnoLast = pgnoLast;
+      pStruct->nSegment++;
+    }
+    fts5StructurePromote(p, 0, pStruct);
+  }
+
+  fts5IndexAutomerge(p, &pStruct, pgnoLast);
+  fts5IndexCrisismerge(p, &pStruct);
+  fts5StructureWrite(p, pStruct);
+  fts5StructureRelease(pStruct);
+}
+
+/*
+** Flush any data stored in the in-memory hash tables to the database.
+*/
+static void fts5IndexFlush(Fts5Index *p){
+  /* Unless it is empty, flush the hash table to disk */
+  if( p->nPendingData ){
+    assert( p->pHash );
+    p->nPendingData = 0;
+    fts5FlushOneHash(p);
+  }
+}
+
+
+static int sqlite3Fts5IndexOptimize(Fts5Index *p){
+  Fts5Structure *pStruct;
+  Fts5Structure *pNew = 0;
+  int nSeg = 0;
+
+  assert( p->rc==SQLITE_OK );
+  fts5IndexFlush(p);
+  pStruct = fts5StructureRead(p);
+
+  if( pStruct ){
+    assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) );
+    nSeg = pStruct->nSegment;
+    if( nSeg>1 ){
+      int nByte = sizeof(Fts5Structure);
+      nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel);
+      pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte);
+    }
+  }
+  if( pNew ){
+    Fts5StructureLevel *pLvl;
+    int nByte = nSeg * sizeof(Fts5StructureSegment);
+    pNew->nLevel = pStruct->nLevel+1;
+    pNew->nRef = 1;
+    pNew->nWriteCounter = pStruct->nWriteCounter;
+    pLvl = &pNew->aLevel[pStruct->nLevel];
+    pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&p->rc, nByte);
+    if( pLvl->aSeg ){
+      int iLvl, iSeg;
+      int iSegOut = 0;
+      for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
+        for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
+          pLvl->aSeg[iSegOut] = pStruct->aLevel[iLvl].aSeg[iSeg];
+          iSegOut++;
+        }
+      }
+      pNew->nSegment = pLvl->nSeg = nSeg;
+    }else{
+      sqlite3_free(pNew);
+      pNew = 0;
+    }
+  }
+
+  if( pNew ){
+    int iLvl = pNew->nLevel-1;
+    while( p->rc==SQLITE_OK && pNew->aLevel[iLvl].nSeg>0 ){
+      int nRem = FTS5_OPT_WORK_UNIT;
+      fts5IndexMergeLevel(p, &pNew, iLvl, &nRem);
+    }
+
+    fts5StructureWrite(p, pNew);
+    fts5StructureRelease(pNew);
+  }
+
+  fts5StructureRelease(pStruct);
+  return fts5IndexReturn(p); 
+}
+
+static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
+  Fts5Structure *pStruct;
+
+  pStruct = fts5StructureRead(p);
+  if( pStruct && pStruct->nLevel ){
+    fts5IndexMerge(p, &pStruct, nMerge);
+    fts5StructureWrite(p, pStruct);
+  }
+  fts5StructureRelease(pStruct);
+
+  return fts5IndexReturn(p);
+}
+
+static void fts5PoslistCallback(
+  Fts5Index *p, 
+  void *pContext, 
+  const u8 *pChunk, int nChunk
+){
+  assert_nc( nChunk>=0 );
+  if( nChunk>0 ){
+    fts5BufferSafeAppendBlob((Fts5Buffer*)pContext, pChunk, nChunk);
+  }
+}
+
+typedef struct PoslistCallbackCtx PoslistCallbackCtx;
+struct PoslistCallbackCtx {
+  Fts5Buffer *pBuf;               /* Append to this buffer */
+  Fts5Colset *pColset;            /* Restrict matches to this column */
+  int eState;                     /* See above */
+};
+
+/*
+** TODO: Make this more efficient!
+*/
+static int fts5IndexColsetTest(Fts5Colset *pColset, int iCol){
+  int i;
+  for(i=0; i<pColset->nCol; i++){
+    if( pColset->aiCol[i]==iCol ) return 1;
+  }
+  return 0;
+}
+
+static void fts5PoslistFilterCallback(
+  Fts5Index *p, 
+  void *pContext, 
+  const u8 *pChunk, int nChunk
+){
+  PoslistCallbackCtx *pCtx = (PoslistCallbackCtx*)pContext;
+  assert_nc( nChunk>=0 );
+  if( nChunk>0 ){
+    /* Search through to find the first varint with value 1. This is the
+    ** start of the next columns hits. */
+    int i = 0;
+    int iStart = 0;
+
+    if( pCtx->eState==2 ){
+      int iCol;
+      fts5FastGetVarint32(pChunk, i, iCol);
+      if( fts5IndexColsetTest(pCtx->pColset, iCol) ){
+        pCtx->eState = 1;
+        fts5BufferSafeAppendVarint(pCtx->pBuf, 1);
+      }else{
+        pCtx->eState = 0;
+      }
+    }
+
+    do {
+      while( i<nChunk && pChunk[i]!=0x01 ){
+        while( pChunk[i] & 0x80 ) i++;
+        i++;
+      }
+      if( pCtx->eState ){
+        fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart);
+      }
+      if( i<nChunk ){
+        int iCol;
+        iStart = i;
+        i++;
+        if( i>=nChunk ){
+          pCtx->eState = 2;
+        }else{
+          fts5FastGetVarint32(pChunk, i, iCol);
+          pCtx->eState = fts5IndexColsetTest(pCtx->pColset, iCol);
+          if( pCtx->eState ){
+            fts5BufferSafeAppendBlob(pCtx->pBuf, &pChunk[iStart], i-iStart);
+            iStart = i;
+          }
+        }
+      }
+    }while( i<nChunk );
+  }
+}
+
+/*
+** Iterator pIter currently points to a valid entry (not EOF). This
+** function appends the position list data for the current entry to
+** buffer pBuf. It does not make a copy of the position-list size
+** field.
+*/
+static void fts5SegiterPoslist(
+  Fts5Index *p,
+  Fts5SegIter *pSeg,
+  Fts5Colset *pColset,
+  Fts5Buffer *pBuf
+){
+  if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos) ){
+    if( pColset==0 ){
+      fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback);
+    }else{
+      PoslistCallbackCtx sCtx;
+      sCtx.pBuf = pBuf;
+      sCtx.pColset = pColset;
+      sCtx.eState = pColset ? fts5IndexColsetTest(pColset, 0) : 1;
+      assert( sCtx.eState==0 || sCtx.eState==1 );
+      fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistFilterCallback);
+    }
+  }
+}
+
+/*
+** IN/OUT parameter (*pa) points to a position list n bytes in size. If
+** the position list contains entries for column iCol, then (*pa) is set
+** to point to the sub-position-list for that column and the number of
+** bytes in it returned. Or, if the argument position list does not
+** contain any entries for column iCol, return 0.
+*/
+static int fts5IndexExtractCol(
+  const u8 **pa,                  /* IN/OUT: Pointer to poslist */
+  int n,                          /* IN: Size of poslist in bytes */
+  int iCol                        /* Column to extract from poslist */
+){
+  int iCurrent = 0;               /* Anything before the first 0x01 is col 0 */
+  const u8 *p = *pa;
+  const u8 *pEnd = &p[n];         /* One byte past end of position list */
+  u8 prev = 0;
+
+  while( iCol!=iCurrent ){
+    /* Advance pointer p until it points to pEnd or an 0x01 byte that is
+    ** not part of a varint */
+    while( (prev & 0x80) || *p!=0x01 ){
+      prev = *p++;
+      if( p==pEnd ) return 0;
+    }
+    *pa = p++;
+    p += fts5GetVarint32(p, iCurrent);
+  }
+
+  /* Advance pointer p until it points to pEnd or an 0x01 byte that is
+  ** not part of a varint */
+  assert( (prev & 0x80)==0 );
+  while( p<pEnd && ((prev & 0x80) || *p!=0x01) ){
+    prev = *p++;
+  }
+  return p - (*pa);
+}
+
+
+/*
+** Iterator pMulti currently points to a valid entry (not EOF). This
+** function appends the following to buffer pBuf:
+**
+**   * The varint iDelta, and
+**   * the position list that currently points to, including the size field.
+**
+** If argument pColset is NULL, then the position list is filtered according
+** to pColset before being appended to the buffer. If this means there are
+** no entries in the position list, nothing is appended to the buffer (not
+** even iDelta).
+**
+** If an error occurs, an error code is left in p->rc. 
+*/
+static int fts5AppendPoslist(
+  Fts5Index *p,
+  i64 iDelta,
+  Fts5IndexIter *pMulti,
+  Fts5Colset *pColset,
+  Fts5Buffer *pBuf
+){
+  if( p->rc==SQLITE_OK ){
+    Fts5SegIter *pSeg = &pMulti->aSeg[ pMulti->aFirst[1].iFirst ];
+    assert( fts5MultiIterEof(p, pMulti)==0 );
+    assert( pSeg->nPos>0 );
+    if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos+9+9) ){
+      int iSv1;
+      int iSv2;
+      int iData;
+
+      /* Append iDelta */
+      iSv1 = pBuf->n;
+      fts5BufferSafeAppendVarint(pBuf, iDelta);
+
+      /* WRITEPOSLISTSIZE */
+      iSv2 = pBuf->n;
+      fts5BufferSafeAppendVarint(pBuf, pSeg->nPos*2);
+      iData = pBuf->n;
+
+      if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf 
+       && (pColset==0 || pColset->nCol==1)
+      ){
+        const u8 *pPos = &pSeg->pLeaf->p[pSeg->iLeafOffset];
+        int nPos;
+        if( pColset ){
+          nPos = fts5IndexExtractCol(&pPos, pSeg->nPos, pColset->aiCol[0]);
+        }else{
+          nPos = pSeg->nPos;
+        }
+        fts5BufferSafeAppendBlob(pBuf, pPos, nPos);
+      }else{
+        fts5SegiterPoslist(p, pSeg, pColset, pBuf);
+      }
+
+      if( pColset ){
+        int nActual = pBuf->n - iData;
+        if( nActual!=pSeg->nPos ){
+          if( nActual==0 ){
+            pBuf->n = iSv1;
+            return 1;
+          }else{
+            int nReq = sqlite3Fts5GetVarintLen((u32)(nActual*2));
+            while( iSv2<(iData-nReq) ){ pBuf->p[iSv2++] = 0x80; }
+            sqlite3Fts5PutVarint(&pBuf->p[iSv2], nActual*2);
+          }
+        }
+      }
+    }
+  }
+
+  return 0;
+}
+
+static void fts5DoclistIterNext(Fts5DoclistIter *pIter){
+  u8 *p = pIter->aPoslist + pIter->nSize + pIter->nPoslist;
+
+  assert( pIter->aPoslist );
+  if( p>=pIter->aEof ){
+    pIter->aPoslist = 0;
+  }else{
+    i64 iDelta;
+
+    p += fts5GetVarint(p, (u64*)&iDelta);
+    pIter->iRowid += iDelta;
+
+    /* Read position list size */
+    if( p[0] & 0x80 ){
+      int nPos;
+      pIter->nSize = fts5GetVarint32(p, nPos);
+      pIter->nPoslist = (nPos>>1);
+    }else{
+      pIter->nPoslist = ((int)(p[0])) >> 1;
+      pIter->nSize = 1;
+    }
+
+    pIter->aPoslist = p;
+  }
+}
+
+static void fts5DoclistIterInit(
+  Fts5Buffer *pBuf, 
+  Fts5DoclistIter *pIter
+){
+  memset(pIter, 0, sizeof(*pIter));
+  pIter->aPoslist = pBuf->p;
+  pIter->aEof = &pBuf->p[pBuf->n];
+  fts5DoclistIterNext(pIter);
+}
+
+#if 0
+/*
+** Append a doclist to buffer pBuf.
+**
+** This function assumes that space within the buffer has already been
+** allocated.
+*/
+static void fts5MergeAppendDocid(
+  Fts5Buffer *pBuf,               /* Buffer to write to */
+  i64 *piLastRowid,               /* IN/OUT: Previous rowid written (if any) */
+  i64 iRowid                      /* Rowid to append */
+){
+  assert( pBuf->n!=0 || (*piLastRowid)==0 );
+  fts5BufferSafeAppendVarint(pBuf, iRowid - *piLastRowid);
+  *piLastRowid = iRowid;
+}
+#endif
+
+#define fts5MergeAppendDocid(pBuf, iLastRowid, iRowid) {       \
+  assert( (pBuf)->n!=0 || (iLastRowid)==0 );                   \
+  fts5BufferSafeAppendVarint((pBuf), (iRowid) - (iLastRowid)); \
+  (iLastRowid) = (iRowid);                                     \
+}
+
+/*
+** Buffers p1 and p2 contain doclists. This function merges the content
+** of the two doclists together and sets buffer p1 to the result before
+** returning.
+**
+** If an error occurs, an error code is left in p->rc. If an error has
+** already occurred, this function is a no-op.
+*/
+static void fts5MergePrefixLists(
+  Fts5Index *p,                   /* FTS5 backend object */
+  Fts5Buffer *p1,                 /* First list to merge */
+  Fts5Buffer *p2                  /* Second list to merge */
+){
+  if( p2->n ){
+    i64 iLastRowid = 0;
+    Fts5DoclistIter i1;
+    Fts5DoclistIter i2;
+    Fts5Buffer out;
+    Fts5Buffer tmp;
+    memset(&out, 0, sizeof(out));
+    memset(&tmp, 0, sizeof(tmp));
+
+    sqlite3Fts5BufferGrow(&p->rc, &out, p1->n + p2->n);
+    fts5DoclistIterInit(p1, &i1);
+    fts5DoclistIterInit(p2, &i2);
+    while( p->rc==SQLITE_OK && (i1.aPoslist!=0 || i2.aPoslist!=0) ){
+      if( i2.aPoslist==0 || (i1.aPoslist && i1.iRowid<i2.iRowid) ){
+        /* Copy entry from i1 */
+        fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid);
+        fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.nPoslist+i1.nSize);
+        fts5DoclistIterNext(&i1);
+      }
+      else if( i1.aPoslist==0 || i2.iRowid!=i1.iRowid ){
+        /* Copy entry from i2 */
+        fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
+        fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.nPoslist+i2.nSize);
+        fts5DoclistIterNext(&i2);
+      }
+      else{
+        i64 iPos1 = 0;
+        i64 iPos2 = 0;
+        int iOff1 = 0;
+        int iOff2 = 0;
+        u8 *a1 = &i1.aPoslist[i1.nSize];
+        u8 *a2 = &i2.aPoslist[i2.nSize];
+
+        Fts5PoslistWriter writer;
+        memset(&writer, 0, sizeof(writer));
+
+        /* Merge the two position lists. */ 
+        fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
+        fts5BufferZero(&tmp);
+
+        sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
+        sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
+
+        while( p->rc==SQLITE_OK && (iPos1>=0 || iPos2>=0) ){
+          i64 iNew;
+          if( iPos2<0 || (iPos1>=0 && iPos1<iPos2) ){
+            iNew = iPos1;
+            sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
+          }else{
+            iNew = iPos2;
+            sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
+            if( iPos1==iPos2 ){
+              sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1,&iPos1);
+            }
+          }
+          p->rc = sqlite3Fts5PoslistWriterAppend(&tmp, &writer, iNew);
+        }
+
+        /* WRITEPOSLISTSIZE */
+        fts5BufferSafeAppendVarint(&out, tmp.n * 2);
+        fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n);
+        fts5DoclistIterNext(&i1);
+        fts5DoclistIterNext(&i2);
+      }
+    }
+
+    fts5BufferSet(&p->rc, p1, out.n, out.p);
+    fts5BufferFree(&tmp);
+    fts5BufferFree(&out);
+  }
+}
+
+static void fts5BufferSwap(Fts5Buffer *p1, Fts5Buffer *p2){
+  Fts5Buffer tmp = *p1;
+  *p1 = *p2;
+  *p2 = tmp;
+}
+
+static void fts5SetupPrefixIter(
+  Fts5Index *p,                   /* Index to read from */
+  int bDesc,                      /* True for "ORDER BY rowid DESC" */
+  const u8 *pToken,               /* Buffer containing prefix to match */
+  int nToken,                     /* Size of buffer pToken in bytes */
+  Fts5Colset *pColset,            /* Restrict matches to these columns */
+  Fts5IndexIter **ppIter          /* OUT: New iterator */
+){
+  Fts5Structure *pStruct;
+  Fts5Buffer *aBuf;
+  const int nBuf = 32;
+
+  aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf);
+  pStruct = fts5StructureRead(p);
+
+  if( aBuf && pStruct ){
+    const int flags = FTS5INDEX_QUERY_SCAN;
+    int i;
+    i64 iLastRowid = 0;
+    Fts5IndexIter *p1 = 0;     /* Iterator used to gather data from index */
+    Fts5Data *pData;
+    Fts5Buffer doclist;
+
+    memset(&doclist, 0, sizeof(doclist));
+    for(fts5MultiIterNew(p, pStruct, 1, flags, pToken, nToken, -1, 0, &p1);
+        fts5MultiIterEof(p, p1)==0;
+        fts5MultiIterNext(p, p1, 0, 0)
+    ){
+      i64 iRowid = fts5MultiIterRowid(p1);
+      int nTerm;
+      const u8 *pTerm = fts5MultiIterTerm(p1, &nTerm);
+      assert_nc( memcmp(pToken, pTerm, MIN(nToken, nTerm))<=0 );
+      if( nTerm<nToken || memcmp(pToken, pTerm, nToken) ) break;
+
+      if( doclist.n>0 && iRowid<=iLastRowid ){
+        for(i=0; p->rc==SQLITE_OK && doclist.n; i++){
+          assert( i<nBuf );
+          if( aBuf[i].n==0 ){
+            fts5BufferSwap(&doclist, &aBuf[i]);
+            fts5BufferZero(&doclist);
+          }else{
+            fts5MergePrefixLists(p, &doclist, &aBuf[i]);
+            fts5BufferZero(&aBuf[i]);
+          }
+        }
+        iLastRowid = 0;
+      }
+
+      if( !fts5AppendPoslist(p, iRowid-iLastRowid, p1, pColset, &doclist) ){
+        iLastRowid = iRowid;
+      }
+    }
+
+    for(i=0; i<nBuf; i++){
+      if( p->rc==SQLITE_OK ){
+        fts5MergePrefixLists(p, &doclist, &aBuf[i]);
+      }
+      fts5BufferFree(&aBuf[i]);
+    }
+    fts5MultiIterFree(p, p1);
+
+    pData = fts5IdxMalloc(p, sizeof(Fts5Data) + doclist.n);
+    if( pData ){
+      pData->p = (u8*)&pData[1];
+      pData->nn = pData->szLeaf = doclist.n;
+      memcpy(pData->p, doclist.p, doclist.n);
+      fts5MultiIterNew2(p, pData, bDesc, ppIter);
+    }
+    fts5BufferFree(&doclist);
+  }
+
+  fts5StructureRelease(pStruct);
+  sqlite3_free(aBuf);
+}
+
+
+/*
+** Indicate that all subsequent calls to sqlite3Fts5IndexWrite() pertain
+** to the document with rowid iRowid.
+*/
+static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
+  assert( p->rc==SQLITE_OK );
+
+  /* Allocate the hash table if it has not already been allocated */
+  if( p->pHash==0 ){
+    p->rc = sqlite3Fts5HashNew(&p->pHash, &p->nPendingData);
+  }
+
+  /* Flush the hash table to disk if required */
+  if( iRowid<p->iWriteRowid 
+   || (iRowid==p->iWriteRowid && p->bDelete==0)
+   || (p->nPendingData > p->nMaxPendingData) 
+  ){
+    fts5IndexFlush(p);
+  }
+
+  p->iWriteRowid = iRowid;
+  p->bDelete = bDelete;
+  return fts5IndexReturn(p);
+}
+
+/*
+** Commit data to disk.
+*/
+static int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit){
+  assert( p->rc==SQLITE_OK );
+  fts5IndexFlush(p);
+  if( bCommit ) fts5CloseReader(p);
+  return fts5IndexReturn(p);
+}
+
+/*
+** Discard any data stored in the in-memory hash tables. Do not write it
+** to the database. Additionally, assume that the contents of the %_data
+** table may have changed on disk. So any in-memory caches of %_data 
+** records must be invalidated.
+*/
+static int sqlite3Fts5IndexRollback(Fts5Index *p){
+  fts5CloseReader(p);
+  fts5IndexDiscardData(p);
+  assert( p->rc==SQLITE_OK );
+  return SQLITE_OK;
+}
+
+/*
+** The %_data table is completely empty when this function is called. This
+** function populates it with the initial structure objects for each index,
+** and the initial version of the "averages" record (a zero-byte blob).
+*/
+static int sqlite3Fts5IndexReinit(Fts5Index *p){
+  Fts5Structure s;
+  memset(&s, 0, sizeof(Fts5Structure));
+  fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0);
+  fts5StructureWrite(p, &s);
+  return fts5IndexReturn(p);
+}
+
+/*
+** Open a new Fts5Index handle. If the bCreate argument is true, create
+** and initialize the underlying %_data table.
+**
+** If successful, set *pp to point to the new object and return SQLITE_OK.
+** Otherwise, set *pp to NULL and return an SQLite error code.
+*/
+static int sqlite3Fts5IndexOpen(
+  Fts5Config *pConfig, 
+  int bCreate, 
+  Fts5Index **pp,
+  char **pzErr
+){
+  int rc = SQLITE_OK;
+  Fts5Index *p;                   /* New object */
+
+  *pp = p = (Fts5Index*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Index));
+  if( rc==SQLITE_OK ){
+    p->pConfig = pConfig;
+    p->nWorkUnit = FTS5_WORK_UNIT;
+    p->nMaxPendingData = 1024*1024;
+    p->zDataTbl = sqlite3Fts5Mprintf(&rc, "%s_data", pConfig->zName);
+    if( p->zDataTbl && bCreate ){
+      rc = sqlite3Fts5CreateTable(
+          pConfig, "data", "id INTEGER PRIMARY KEY, block BLOB", 0, pzErr
+      );
+      if( rc==SQLITE_OK ){
+        rc = sqlite3Fts5CreateTable(pConfig, "idx", 
+            "segid, term, pgno, PRIMARY KEY(segid, term)", 
+            1, pzErr
+        );
+      }
+      if( rc==SQLITE_OK ){
+        rc = sqlite3Fts5IndexReinit(p);
+      }
+    }
+  }
+
+  assert( rc!=SQLITE_OK || p->rc==SQLITE_OK );
+  if( rc ){
+    sqlite3Fts5IndexClose(p);
+    *pp = 0;
+  }
+  return rc;
+}
+
+/*
+** Close a handle opened by an earlier call to sqlite3Fts5IndexOpen().
+*/
+static int sqlite3Fts5IndexClose(Fts5Index *p){
+  int rc = SQLITE_OK;
+  if( p ){
+    assert( p->pReader==0 );
+    sqlite3_finalize(p->pWriter);
+    sqlite3_finalize(p->pDeleter);
+    sqlite3_finalize(p->pIdxWriter);
+    sqlite3_finalize(p->pIdxDeleter);
+    sqlite3_finalize(p->pIdxSelect);
+    sqlite3Fts5HashFree(p->pHash);
+    sqlite3_free(p->zDataTbl);
+    sqlite3_free(p);
+  }
+  return rc;
+}
+
+/*
+** Argument p points to a buffer containing utf-8 text that is n bytes in 
+** size. Return the number of bytes in the nChar character prefix of the
+** buffer, or 0 if there are less than nChar characters in total.
+*/
+static int fts5IndexCharlenToBytelen(const char *p, int nByte, int nChar){
+  int n = 0;
+  int i;
+  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++;
+    }
+  }
+  return n;
+}
+
+/*
+** pIn is a UTF-8 encoded string, nIn bytes in size. Return the number of
+** unicode characters in the string.
+*/
+static int fts5IndexCharlen(const char *pIn, int nIn){
+  int nChar = 0;            
+  int i = 0;
+  while( i<nIn ){
+    if( (unsigned char)pIn[i++]>=0xc0 ){
+      while( i<nIn && (pIn[i] & 0xc0)==0x80 ) i++;
+    }
+    nChar++;
+  }
+  return nChar;
+}
+
+/*
+** Insert or remove data to or from the index. Each time a document is 
+** added to or removed from the index, this function is called one or more
+** times.
+**
+** For an insert, it must be called once for each token in the new document.
+** If the operation is a delete, it must be called (at least) once for each
+** unique token in the document with an iCol value less than zero. The iPos
+** argument is ignored for a delete.
+*/
+static int sqlite3Fts5IndexWrite(
+  Fts5Index *p,                   /* Index to write to */
+  int iCol,                       /* Column token appears in (-ve -> delete) */
+  int iPos,                       /* Position of token within column */
+  const char *pToken, int nToken  /* Token to add or remove to or from index */
+){
+  int i;                          /* Used to iterate through indexes */
+  int rc = SQLITE_OK;             /* Return code */
+  Fts5Config *pConfig = p->pConfig;
+
+  assert( p->rc==SQLITE_OK );
+  assert( (iCol<0)==p->bDelete );
+
+  /* Add the entry to the main terms index. */
+  rc = sqlite3Fts5HashWrite(
+      p->pHash, p->iWriteRowid, iCol, iPos, FTS5_MAIN_PREFIX, pToken, nToken
+  );
+
+  for(i=0; i<pConfig->nPrefix && rc==SQLITE_OK; i++){
+    int nByte = fts5IndexCharlenToBytelen(pToken, nToken, pConfig->aPrefix[i]);
+    if( nByte ){
+      rc = sqlite3Fts5HashWrite(p->pHash, 
+          p->iWriteRowid, iCol, iPos, FTS5_MAIN_PREFIX+i+1, pToken, nByte
+      );
+    }
+  }
+
+  return rc;
+}
+
+/*
+** Open a new iterator to iterate though all rowid that match the 
+** specified token or token prefix.
+*/
+static int sqlite3Fts5IndexQuery(
+  Fts5Index *p,                   /* FTS index to query */
+  const char *pToken, int nToken, /* Token (or prefix) to query for */
+  int flags,                      /* Mask of FTS5INDEX_QUERY_X flags */
+  Fts5Colset *pColset,            /* Match these columns only */
+  Fts5IndexIter **ppIter          /* OUT: New iterator object */
+){
+  Fts5Config *pConfig = p->pConfig;
+  Fts5IndexIter *pRet = 0;
+  int iIdx = 0;
+  Fts5Buffer buf = {0, 0, 0};
+
+  /* If the QUERY_SCAN flag is set, all other flags must be clear. */
+  assert( (flags & FTS5INDEX_QUERY_SCAN)==0
+       || (flags & FTS5INDEX_QUERY_SCAN)==FTS5INDEX_QUERY_SCAN
+  );
+
+  if( sqlite3Fts5BufferGrow(&p->rc, &buf, nToken+1)==0 ){
+    memcpy(&buf.p[1], pToken, nToken);
+
+#ifdef SQLITE_DEBUG
+    /* If the QUERY_TEST_NOIDX flag was specified, then this must be a
+    ** prefix-query. Instead of using a prefix-index (if one exists), 
+    ** evaluate the prefix query using the main FTS index. This is used
+    ** for internal sanity checking by the integrity-check in debug 
+    ** mode only.  */
+    if( pConfig->bPrefixIndex==0 || (flags & FTS5INDEX_QUERY_TEST_NOIDX) ){
+      assert( flags & FTS5INDEX_QUERY_PREFIX );
+      iIdx = 1+pConfig->nPrefix;
+    }else
+#endif
+    if( flags & FTS5INDEX_QUERY_PREFIX ){
+      int nChar = fts5IndexCharlen(pToken, nToken);
+      for(iIdx=1; iIdx<=pConfig->nPrefix; iIdx++){
+        if( pConfig->aPrefix[iIdx-1]==nChar ) break;
+      }
+    }
+
+    if( iIdx<=pConfig->nPrefix ){
+      Fts5Structure *pStruct = fts5StructureRead(p);
+      buf.p[0] = FTS5_MAIN_PREFIX + iIdx;
+      if( pStruct ){
+        fts5MultiIterNew(p, pStruct, 1, flags, buf.p, nToken+1, -1, 0, &pRet);
+        fts5StructureRelease(pStruct);
+      }
+    }else{
+      int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0;
+      buf.p[0] = FTS5_MAIN_PREFIX;
+      fts5SetupPrefixIter(p, bDesc, buf.p, nToken+1, pColset, &pRet);
+    }
+
+    if( p->rc ){
+      sqlite3Fts5IterClose(pRet);
+      pRet = 0;
+      fts5CloseReader(p);
+    }
+    *ppIter = pRet;
+    sqlite3Fts5BufferFree(&buf);
+  }
+  return fts5IndexReturn(p);
+}
+
+/*
+** Return true if the iterator passed as the only argument is at EOF.
+*/
+static int sqlite3Fts5IterEof(Fts5IndexIter *pIter){
+  assert( pIter->pIndex->rc==SQLITE_OK );
+  return pIter->bEof;
+}
+
+/*
+** Move to the next matching rowid. 
+*/
+static int sqlite3Fts5IterNext(Fts5IndexIter *pIter){
+  assert( pIter->pIndex->rc==SQLITE_OK );
+  fts5MultiIterNext(pIter->pIndex, pIter, 0, 0);
+  return fts5IndexReturn(pIter->pIndex);
+}
+
+/*
+** Move to the next matching term/rowid. Used by the fts5vocab module.
+*/
+static int sqlite3Fts5IterNextScan(Fts5IndexIter *pIter){
+  Fts5Index *p = pIter->pIndex;
+
+  assert( pIter->pIndex->rc==SQLITE_OK );
+
+  fts5MultiIterNext(p, pIter, 0, 0);
+  if( p->rc==SQLITE_OK ){
+    Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
+    if( pSeg->pLeaf && pSeg->term.p[0]!=FTS5_MAIN_PREFIX ){
+      fts5DataRelease(pSeg->pLeaf);
+      pSeg->pLeaf = 0;
+      pIter->bEof = 1;
+    }
+  }
+
+  return fts5IndexReturn(pIter->pIndex);
+}
+
+/*
+** Move to the next matching rowid that occurs at or after iMatch. The
+** definition of "at or after" depends on whether this iterator iterates
+** in ascending or descending rowid order.
+*/
+static int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIter, i64 iMatch){
+  fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch);
+  return fts5IndexReturn(pIter->pIndex);
+}
+
+/*
+** Return the current rowid.
+*/
+static i64 sqlite3Fts5IterRowid(Fts5IndexIter *pIter){
+  return fts5MultiIterRowid(pIter);
+}
+
+/*
+** Return the current term.
+*/
+static const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIter, int *pn){
+  int n;
+  const char *z = (const char*)fts5MultiIterTerm(pIter, &n);
+  *pn = n-1;
+  return &z[1];
+}
+
+
+static int fts5IndexExtractColset (
+  Fts5Colset *pColset,            /* Colset to filter on */
+  const u8 *pPos, int nPos,       /* Position list */
+  Fts5Buffer *pBuf                /* Output buffer */
+){
+  int rc = SQLITE_OK;
+  int i;
+
+  fts5BufferZero(pBuf);
+  for(i=0; i<pColset->nCol; i++){
+    const u8 *pSub = pPos;
+    int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]);
+    if( nSub ){
+      fts5BufferAppendBlob(&rc, pBuf, nSub, pSub);
+    }
+  }
+  return rc;
+}
+
+
+/*
+** Return a pointer to a buffer containing a copy of the position list for
+** the current entry. Output variable *pn is set to the size of the buffer 
+** in bytes before returning.
+**
+** The returned position list does not include the "number of bytes" varint
+** field that starts the position list on disk.
+*/
+static int sqlite3Fts5IterPoslist(
+  Fts5IndexIter *pIter, 
+  Fts5Colset *pColset,            /* Column filter (or NULL) */
+  const u8 **pp,                  /* OUT: Pointer to position-list data */
+  int *pn,                        /* OUT: Size of position-list in bytes */
+  i64 *piRowid                    /* OUT: Current rowid */
+){
+  Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
+  assert( pIter->pIndex->rc==SQLITE_OK );
+  *piRowid = pSeg->iRowid;
+  if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){
+    u8 *pPos = &pSeg->pLeaf->p[pSeg->iLeafOffset];
+    if( pColset==0 || pIter->bFiltered ){
+      *pn = pSeg->nPos;
+      *pp = pPos;
+    }else if( pColset->nCol==1 ){
+      *pp = pPos;
+      *pn = fts5IndexExtractCol(pp, pSeg->nPos, pColset->aiCol[0]);
+    }else{
+      fts5BufferZero(&pIter->poslist);
+      fts5IndexExtractColset(pColset, pPos, pSeg->nPos, &pIter->poslist);
+      *pp = pIter->poslist.p;
+      *pn = pIter->poslist.n;
+    }
+  }else{
+    fts5BufferZero(&pIter->poslist);
+    fts5SegiterPoslist(pIter->pIndex, pSeg, pColset, &pIter->poslist);
+    *pp = pIter->poslist.p;
+    *pn = pIter->poslist.n;
+  }
+  return fts5IndexReturn(pIter->pIndex);
+}
+
+/*
+** This function is similar to sqlite3Fts5IterPoslist(), except that it
+** copies the position list into the buffer supplied as the second 
+** argument.
+*/
+static int sqlite3Fts5IterPoslistBuffer(Fts5IndexIter *pIter, Fts5Buffer *pBuf){
+  Fts5Index *p = pIter->pIndex;
+  Fts5SegIter *pSeg = &pIter->aSeg[ pIter->aFirst[1].iFirst ];
+  assert( p->rc==SQLITE_OK );
+  fts5BufferZero(pBuf);
+  fts5SegiterPoslist(p, pSeg, 0, pBuf);
+  return fts5IndexReturn(p);
+}
+
+/*
+** Close an iterator opened by an earlier call to sqlite3Fts5IndexQuery().
+*/
+static void sqlite3Fts5IterClose(Fts5IndexIter *pIter){
+  if( pIter ){
+    Fts5Index *pIndex = pIter->pIndex;
+    fts5MultiIterFree(pIter->pIndex, pIter);
+    fts5CloseReader(pIndex);
+  }
+}
+
+/*
+** Read and decode the "averages" record from the database. 
+**
+** Parameter anSize must point to an array of size nCol, where nCol is
+** the number of user defined columns in the FTS table.
+*/
+static int sqlite3Fts5IndexGetAverages(Fts5Index *p, i64 *pnRow, i64 *anSize){
+  int nCol = p->pConfig->nCol;
+  Fts5Data *pData;
+
+  *pnRow = 0;
+  memset(anSize, 0, sizeof(i64) * nCol);
+  pData = fts5DataRead(p, FTS5_AVERAGES_ROWID);
+  if( p->rc==SQLITE_OK && pData->nn ){
+    int i = 0;
+    int iCol;
+    i += fts5GetVarint(&pData->p[i], (u64*)pnRow);
+    for(iCol=0; i<pData->nn && iCol<nCol; iCol++){
+      i += fts5GetVarint(&pData->p[i], (u64*)&anSize[iCol]);
+    }
+  }
+
+  fts5DataRelease(pData);
+  return fts5IndexReturn(p);
+}
+
+/*
+** Replace the current "averages" record with the contents of the buffer 
+** supplied as the second argument.
+*/
+static int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8 *pData, int nData){
+  assert( p->rc==SQLITE_OK );
+  fts5DataWrite(p, FTS5_AVERAGES_ROWID, pData, nData);
+  return fts5IndexReturn(p);
+}
+
+/*
+** Return the total number of blocks this module has read from the %_data
+** table since it was created.
+*/
+static int sqlite3Fts5IndexReads(Fts5Index *p){
+  return p->nRead;
+}
+
+/*
+** Set the 32-bit cookie value stored at the start of all structure 
+** records to the value passed as the second argument.
+**
+** Return SQLITE_OK if successful, or an SQLite error code if an error
+** occurs.
+*/
+static int sqlite3Fts5IndexSetCookie(Fts5Index *p, int iNew){
+  int rc;                              /* Return code */
+  Fts5Config *pConfig = p->pConfig;    /* Configuration object */
+  u8 aCookie[4];                       /* Binary representation of iNew */
+  sqlite3_blob *pBlob = 0;
+
+  assert( p->rc==SQLITE_OK );
+  sqlite3Fts5Put32(aCookie, iNew);
+
+  rc = sqlite3_blob_open(pConfig->db, pConfig->zDb, p->zDataTbl, 
+      "block", FTS5_STRUCTURE_ROWID, 1, &pBlob
+  );
+  if( rc==SQLITE_OK ){
+    sqlite3_blob_write(pBlob, aCookie, 4, 0);
+    rc = sqlite3_blob_close(pBlob);
+  }
+
+  return rc;
+}
+
+static int sqlite3Fts5IndexLoadConfig(Fts5Index *p){
+  Fts5Structure *pStruct;
+  pStruct = fts5StructureRead(p);
+  fts5StructureRelease(pStruct);
+  return fts5IndexReturn(p);
+}
+
+
+/*************************************************************************
+**************************************************************************
+** Below this point is the implementation of the integrity-check 
+** functionality.
+*/
+
+/*
+** Return a simple checksum value based on the arguments.
+*/
+static u64 fts5IndexEntryCksum(
+  i64 iRowid, 
+  int iCol, 
+  int iPos, 
+  int iIdx,
+  const char *pTerm,
+  int nTerm
+){
+  int i;
+  u64 ret = iRowid;
+  ret += (ret<<3) + iCol;
+  ret += (ret<<3) + iPos;
+  if( iIdx>=0 ) ret += (ret<<3) + (FTS5_MAIN_PREFIX + iIdx);
+  for(i=0; i<nTerm; i++) ret += (ret<<3) + pTerm[i];
+  return ret;
+}
+
+#ifdef SQLITE_DEBUG
+/*
+** This function is purely an internal test. It does not contribute to 
+** FTS functionality, or even the integrity-check, in any way.
+**
+** Instead, it tests that the same set of pgno/rowid combinations are 
+** visited regardless of whether the doclist-index identified by parameters
+** iSegid/iLeaf is iterated in forwards or reverse order.
+*/
+static void fts5TestDlidxReverse(
+  Fts5Index *p, 
+  int iSegid,                     /* Segment id to load from */
+  int iLeaf                       /* Load doclist-index for this leaf */
+){
+  Fts5DlidxIter *pDlidx = 0;
+  u64 cksum1 = 13;
+  u64 cksum2 = 13;
+
+  for(pDlidx=fts5DlidxIterInit(p, 0, iSegid, iLeaf);
+      fts5DlidxIterEof(p, pDlidx)==0;
+      fts5DlidxIterNext(p, pDlidx)
+  ){
+    i64 iRowid = fts5DlidxIterRowid(pDlidx);
+    int pgno = fts5DlidxIterPgno(pDlidx);
+    assert( pgno>iLeaf );
+    cksum1 += iRowid + ((i64)pgno<<32);
+  }
+  fts5DlidxIterFree(pDlidx);
+  pDlidx = 0;
+
+  for(pDlidx=fts5DlidxIterInit(p, 1, iSegid, iLeaf);
+      fts5DlidxIterEof(p, pDlidx)==0;
+      fts5DlidxIterPrev(p, pDlidx)
+  ){
+    i64 iRowid = fts5DlidxIterRowid(pDlidx);
+    int pgno = fts5DlidxIterPgno(pDlidx);
+    assert( fts5DlidxIterPgno(pDlidx)>iLeaf );
+    cksum2 += iRowid + ((i64)pgno<<32);
+  }
+  fts5DlidxIterFree(pDlidx);
+  pDlidx = 0;
+
+  if( p->rc==SQLITE_OK && cksum1!=cksum2 ) p->rc = FTS5_CORRUPT;
+}
+
+static int fts5QueryCksum(
+  Fts5Index *p,                   /* Fts5 index object */
+  int iIdx,
+  const char *z,                  /* Index key to query for */
+  int n,                          /* Size of index key in bytes */
+  int flags,                      /* Flags for Fts5IndexQuery */
+  u64 *pCksum                     /* IN/OUT: Checksum value */
+){
+  u64 cksum = *pCksum;
+  Fts5IndexIter *pIdxIter = 0;
+  int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIdxIter);
+
+  while( rc==SQLITE_OK && 0==sqlite3Fts5IterEof(pIdxIter) ){
+    i64 dummy;
+    const u8 *pPos;
+    int nPos;
+    i64 rowid = sqlite3Fts5IterRowid(pIdxIter);
+    rc = sqlite3Fts5IterPoslist(pIdxIter, 0, &pPos, &nPos, &dummy);
+    if( rc==SQLITE_OK ){
+      Fts5PoslistReader sReader;
+      for(sqlite3Fts5PoslistReaderInit(pPos, nPos, &sReader);
+          sReader.bEof==0;
+          sqlite3Fts5PoslistReaderNext(&sReader)
+      ){
+        int iCol = FTS5_POS2COLUMN(sReader.iPos);
+        int iOff = FTS5_POS2OFFSET(sReader.iPos);
+        cksum ^= fts5IndexEntryCksum(rowid, iCol, iOff, iIdx, z, n);
+      }
+      rc = sqlite3Fts5IterNext(pIdxIter);
+    }
+  }
+  sqlite3Fts5IterClose(pIdxIter);
+
+  *pCksum = cksum;
+  return rc;
+}
+
+
+/*
+** This function is also purely an internal test. It does not contribute to 
+** FTS functionality, or even the integrity-check, in any way.
+*/
+static void fts5TestTerm(
+  Fts5Index *p, 
+  Fts5Buffer *pPrev,              /* Previous term */
+  const char *z, int n,           /* Possibly new term to test */
+  u64 expected,
+  u64 *pCksum
+){
+  int rc = p->rc;
+  if( pPrev->n==0 ){
+    fts5BufferSet(&rc, pPrev, n, (const u8*)z);
+  }else
+  if( rc==SQLITE_OK && (pPrev->n!=n || memcmp(pPrev->p, z, n)) ){
+    u64 cksum3 = *pCksum;
+    const char *zTerm = (const char*)&pPrev->p[1];  /* term sans prefix-byte */
+    int nTerm = pPrev->n-1;            /* Size of zTerm in bytes */
+    int iIdx = (pPrev->p[0] - FTS5_MAIN_PREFIX);
+    int flags = (iIdx==0 ? 0 : FTS5INDEX_QUERY_PREFIX);
+    u64 ck1 = 0;
+    u64 ck2 = 0;
+
+    /* Check that the results returned for ASC and DESC queries are
+    ** the same. If not, call this corruption.  */
+    rc = fts5QueryCksum(p, iIdx, zTerm, nTerm, flags, &ck1);
+    if( rc==SQLITE_OK ){
+      int f = flags|FTS5INDEX_QUERY_DESC;
+      rc = fts5QueryCksum(p, iIdx, zTerm, nTerm, f, &ck2);
+    }
+    if( rc==SQLITE_OK && ck1!=ck2 ) rc = FTS5_CORRUPT;
+
+    /* If this is a prefix query, check that the results returned if the
+    ** the index is disabled are the same. In both ASC and DESC order. 
+    **
+    ** This check may only be performed if the hash table is empty. This
+    ** is because the hash table only supports a single scan query at
+    ** a time, and the multi-iter loop from which this function is called
+    ** is already performing such a scan. */
+    if( p->nPendingData==0 ){
+      if( iIdx>0 && rc==SQLITE_OK ){
+        int f = flags|FTS5INDEX_QUERY_TEST_NOIDX;
+        ck2 = 0;
+        rc = fts5QueryCksum(p, iIdx, zTerm, nTerm, f, &ck2);
+        if( rc==SQLITE_OK && ck1!=ck2 ) rc = FTS5_CORRUPT;
+      }
+      if( iIdx>0 && rc==SQLITE_OK ){
+        int f = flags|FTS5INDEX_QUERY_TEST_NOIDX|FTS5INDEX_QUERY_DESC;
+        ck2 = 0;
+        rc = fts5QueryCksum(p, iIdx, zTerm, nTerm, f, &ck2);
+        if( rc==SQLITE_OK && ck1!=ck2 ) rc = FTS5_CORRUPT;
+      }
+    }
+
+    cksum3 ^= ck1;
+    fts5BufferSet(&rc, pPrev, n, (const u8*)z);
+
+    if( rc==SQLITE_OK && cksum3!=expected ){
+      rc = FTS5_CORRUPT;
+    }
+    *pCksum = cksum3;
+  }
+  p->rc = rc;
+}
+#else
+# define fts5TestDlidxReverse(x,y,z)
+# define fts5TestTerm(u,v,w,x,y,z)
+#endif
+
+/*
+** Check that:
+**
+**   1) All leaves of pSeg between iFirst and iLast (inclusive) exist and
+**      contain zero terms.
+**   2) All leaves of pSeg between iNoRowid and iLast (inclusive) exist and
+**      contain zero rowids.
+*/
+static void fts5IndexIntegrityCheckEmpty(
+  Fts5Index *p,
+  Fts5StructureSegment *pSeg,     /* Segment to check internal consistency */
+  int iFirst,
+  int iNoRowid,
+  int iLast
+){
+  int i;
+
+  /* Now check that the iter.nEmpty leaves following the current leaf
+  ** (a) exist and (b) contain no terms. */
+  for(i=iFirst; p->rc==SQLITE_OK && i<=iLast; i++){
+    Fts5Data *pLeaf = fts5DataRead(p, FTS5_SEGMENT_ROWID(pSeg->iSegid, i));
+    if( pLeaf ){
+      if( !fts5LeafIsTermless(pLeaf) ) p->rc = FTS5_CORRUPT;
+      if( i>=iNoRowid && 0!=fts5LeafFirstRowidOff(pLeaf) ) p->rc = FTS5_CORRUPT;
+    }
+    fts5DataRelease(pLeaf);
+  }
+}
+
+static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){
+  int iTermOff = 0;
+  int ii;
+
+  Fts5Buffer buf1 = {0,0,0};
+  Fts5Buffer buf2 = {0,0,0};
+
+  ii = pLeaf->szLeaf;
+  while( ii<pLeaf->nn && p->rc==SQLITE_OK ){
+    int res;
+    int iOff;
+    int nIncr;
+
+    ii += fts5GetVarint32(&pLeaf->p[ii], nIncr);
+    iTermOff += nIncr;
+    iOff = iTermOff;
+
+    if( iOff>=pLeaf->szLeaf ){
+      p->rc = FTS5_CORRUPT;
+    }else if( iTermOff==nIncr ){
+      int nByte;
+      iOff += fts5GetVarint32(&pLeaf->p[iOff], nByte);
+      if( (iOff+nByte)>pLeaf->szLeaf ){
+        p->rc = FTS5_CORRUPT;
+      }else{
+        fts5BufferSet(&p->rc, &buf1, nByte, &pLeaf->p[iOff]);
+      }
+    }else{
+      int nKeep, nByte;
+      iOff += fts5GetVarint32(&pLeaf->p[iOff], nKeep);
+      iOff += fts5GetVarint32(&pLeaf->p[iOff], nByte);
+      if( nKeep>buf1.n || (iOff+nByte)>pLeaf->szLeaf ){
+        p->rc = FTS5_CORRUPT;
+      }else{
+        buf1.n = nKeep;
+        fts5BufferAppendBlob(&p->rc, &buf1, nByte, &pLeaf->p[iOff]);
+      }
+
+      if( p->rc==SQLITE_OK ){
+        res = fts5BufferCompare(&buf1, &buf2);
+        if( res<=0 ) p->rc = FTS5_CORRUPT;
+      }
+    }
+    fts5BufferSet(&p->rc, &buf2, buf1.n, buf1.p);
+  }
+
+  fts5BufferFree(&buf1);
+  fts5BufferFree(&buf2);
+}
+
+static void fts5IndexIntegrityCheckSegment(
+  Fts5Index *p,                   /* FTS5 backend object */
+  Fts5StructureSegment *pSeg      /* Segment to check internal consistency */
+){
+  Fts5Config *pConfig = p->pConfig;
+  sqlite3_stmt *pStmt = 0;
+  int rc2;
+  int iIdxPrevLeaf = pSeg->pgnoFirst-1;
+  int iDlidxPrevLeaf = pSeg->pgnoLast;
+
+  if( pSeg->pgnoFirst==0 ) return;
+
+  fts5IndexPrepareStmt(p, &pStmt, sqlite3_mprintf(
+      "SELECT segid, term, (pgno>>1), (pgno&1) FROM %Q.'%q_idx' WHERE segid=%d",
+      pConfig->zDb, pConfig->zName, pSeg->iSegid
+  ));
+
+  /* Iterate through the b-tree hierarchy.  */
+  while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+    i64 iRow;                     /* Rowid for this leaf */
+    Fts5Data *pLeaf;              /* Data for this leaf */
+
+    int nIdxTerm = sqlite3_column_bytes(pStmt, 1);
+    const char *zIdxTerm = (const char*)sqlite3_column_text(pStmt, 1);
+    int iIdxLeaf = sqlite3_column_int(pStmt, 2);
+    int bIdxDlidx = sqlite3_column_int(pStmt, 3);
+
+    /* If the leaf in question has already been trimmed from the segment, 
+    ** ignore this b-tree entry. Otherwise, load it into memory. */
+    if( iIdxLeaf<pSeg->pgnoFirst ) continue;
+    iRow = FTS5_SEGMENT_ROWID(pSeg->iSegid, iIdxLeaf);
+    pLeaf = fts5DataRead(p, iRow);
+    if( pLeaf==0 ) break;
+
+    /* Check that the leaf contains at least one term, and that it is equal
+    ** to or larger than the split-key in zIdxTerm.  Also check that if there
+    ** is also a rowid pointer within the leaf page header, it points to a
+    ** location before the term.  */
+    if( pLeaf->nn<=pLeaf->szLeaf ){
+      p->rc = FTS5_CORRUPT;
+    }else{
+      int iOff;                   /* Offset of first term on leaf */
+      int iRowidOff;              /* Offset of first rowid on leaf */
+      int nTerm;                  /* Size of term on leaf in bytes */
+      int res;                    /* Comparison of term and split-key */
+
+      iOff = fts5LeafFirstTermOff(pLeaf);
+      iRowidOff = fts5LeafFirstRowidOff(pLeaf);
+      if( iRowidOff>=iOff ){
+        p->rc = FTS5_CORRUPT;
+      }else{
+        iOff += fts5GetVarint32(&pLeaf->p[iOff], nTerm);
+        res = memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm));
+        if( res==0 ) res = nTerm - nIdxTerm;
+        if( res<0 ) p->rc = FTS5_CORRUPT;
+      }
+
+      fts5IntegrityCheckPgidx(p, pLeaf);
+    }
+    fts5DataRelease(pLeaf);
+    if( p->rc ) break;
+
+
+    /* Now check that the iter.nEmpty leaves following the current leaf
+    ** (a) exist and (b) contain no terms. */
+    fts5IndexIntegrityCheckEmpty(
+        p, pSeg, iIdxPrevLeaf+1, iDlidxPrevLeaf+1, iIdxLeaf-1
+    );
+    if( p->rc ) break;
+
+    /* If there is a doclist-index, check that it looks right. */
+    if( bIdxDlidx ){
+      Fts5DlidxIter *pDlidx = 0;  /* For iterating through doclist index */
+      int iPrevLeaf = iIdxLeaf;
+      int iSegid = pSeg->iSegid;
+      int iPg = 0;
+      i64 iKey;
+
+      for(pDlidx=fts5DlidxIterInit(p, 0, iSegid, iIdxLeaf);
+          fts5DlidxIterEof(p, pDlidx)==0;
+          fts5DlidxIterNext(p, pDlidx)
+      ){
+
+        /* Check any rowid-less pages that occur before the current leaf. */
+        for(iPg=iPrevLeaf+1; iPg<fts5DlidxIterPgno(pDlidx); iPg++){
+          iKey = FTS5_SEGMENT_ROWID(iSegid, iPg);
+          pLeaf = fts5DataRead(p, iKey);
+          if( pLeaf ){
+            if( fts5LeafFirstRowidOff(pLeaf)!=0 ) p->rc = FTS5_CORRUPT;
+            fts5DataRelease(pLeaf);
+          }
+        }
+        iPrevLeaf = fts5DlidxIterPgno(pDlidx);
+
+        /* Check that the leaf page indicated by the iterator really does
+        ** contain the rowid suggested by the same. */
+        iKey = FTS5_SEGMENT_ROWID(iSegid, iPrevLeaf);
+        pLeaf = fts5DataRead(p, iKey);
+        if( pLeaf ){
+          i64 iRowid;
+          int iRowidOff = fts5LeafFirstRowidOff(pLeaf);
+          ASSERT_SZLEAF_OK(pLeaf);
+          if( iRowidOff>=pLeaf->szLeaf ){
+            p->rc = FTS5_CORRUPT;
+          }else{
+            fts5GetVarint(&pLeaf->p[iRowidOff], (u64*)&iRowid);
+            if( iRowid!=fts5DlidxIterRowid(pDlidx) ) p->rc = FTS5_CORRUPT;
+          }
+          fts5DataRelease(pLeaf);
+        }
+      }
+
+      iDlidxPrevLeaf = iPg;
+      fts5DlidxIterFree(pDlidx);
+      fts5TestDlidxReverse(p, iSegid, iIdxLeaf);
+    }else{
+      iDlidxPrevLeaf = pSeg->pgnoLast;
+      /* TODO: Check there is no doclist index */
+    }
+
+    iIdxPrevLeaf = iIdxLeaf;
+  }
+
+  rc2 = sqlite3_finalize(pStmt);
+  if( p->rc==SQLITE_OK ) p->rc = rc2;
+
+  /* Page iter.iLeaf must now be the rightmost leaf-page in the segment */
+#if 0
+  if( p->rc==SQLITE_OK && iter.iLeaf!=pSeg->pgnoLast ){
+    p->rc = FTS5_CORRUPT;
+  }
+#endif
+}
+
+
+/*
+** Run internal checks to ensure that the FTS index (a) is internally 
+** consistent and (b) contains entries for which the XOR of the checksums
+** as calculated by fts5IndexEntryCksum() is cksum.
+**
+** Return SQLITE_CORRUPT if any of the internal checks fail, or if the
+** checksum does not match. Return SQLITE_OK if all checks pass without
+** error, or some other SQLite error code if another error (e.g. OOM)
+** occurs.
+*/
+static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
+  u64 cksum2 = 0;                 /* Checksum based on contents of indexes */
+  Fts5Buffer poslist = {0,0,0};   /* Buffer used to hold a poslist */
+  Fts5IndexIter *pIter;           /* Used to iterate through entire index */
+  Fts5Structure *pStruct;         /* Index structure */
+
+  /* Used by extra internal tests only run if NDEBUG is not defined */
+  u64 cksum3 = 0;                 /* Checksum based on contents of indexes */
+  Fts5Buffer term = {0,0,0};      /* Buffer used to hold most recent term */
+  
+  /* Load the FTS index structure */
+  pStruct = fts5StructureRead(p);
+
+  /* Check that the internal nodes of each segment match the leaves */
+  if( pStruct ){
+    int iLvl, iSeg;
+    for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
+      for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
+        Fts5StructureSegment *pSeg = &pStruct->aLevel[iLvl].aSeg[iSeg];
+        fts5IndexIntegrityCheckSegment(p, pSeg);
+      }
+    }
+  }
+
+  /* The cksum argument passed to this function is a checksum calculated
+  ** based on all expected entries in the FTS index (including prefix index
+  ** entries). This block checks that a checksum calculated based on the
+  ** actual contents of FTS index is identical.
+  **
+  ** Two versions of the same checksum are calculated. The first (stack
+  ** variable cksum2) based on entries extracted from the full-text index
+  ** while doing a linear scan of each individual index in turn. 
+  **
+  ** As each term visited by the linear scans, a separate query for the
+  ** same term is performed. cksum3 is calculated based on the entries
+  ** extracted by these queries.
+  */
+  for(fts5MultiIterNew(p, pStruct, 0, 0, 0, 0, -1, 0, &pIter);
+      fts5MultiIterEof(p, pIter)==0;
+      fts5MultiIterNext(p, pIter, 0, 0)
+  ){
+    int n;                      /* Size of term in bytes */
+    i64 iPos = 0;               /* Position read from poslist */
+    int iOff = 0;               /* Offset within poslist */
+    i64 iRowid = fts5MultiIterRowid(pIter);
+    char *z = (char*)fts5MultiIterTerm(pIter, &n);
+
+    /* If this is a new term, query for it. Update cksum3 with the results. */
+    fts5TestTerm(p, &term, z, n, cksum2, &cksum3);
+
+    poslist.n = 0;
+    fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst] , 0, &poslist);
+    while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){
+      int iCol = FTS5_POS2COLUMN(iPos);
+      int iTokOff = FTS5_POS2OFFSET(iPos);
+      cksum2 ^= fts5IndexEntryCksum(iRowid, iCol, iTokOff, -1, z, n);
+    }
+  }
+  fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3);
+
+  fts5MultiIterFree(p, pIter);
+  if( p->rc==SQLITE_OK && cksum!=cksum2 ) p->rc = FTS5_CORRUPT;
+
+  fts5StructureRelease(pStruct);
+  fts5BufferFree(&term);
+  fts5BufferFree(&poslist);
+  return fts5IndexReturn(p);
+}
+
+
+/*
+** Calculate and return a checksum that is the XOR of the index entry
+** checksum of all entries that would be generated by the token specified
+** by the final 5 arguments.
+*/
+static u64 sqlite3Fts5IndexCksum(
+  Fts5Config *pConfig,            /* Configuration object */
+  i64 iRowid,                     /* Document term appears in */
+  int iCol,                       /* Column term appears in */
+  int iPos,                       /* Position term appears in */
+  const char *pTerm, int nTerm    /* Term at iPos */
+){
+  u64 ret = 0;                    /* Return value */
+  int iIdx;                       /* For iterating through indexes */
+
+  ret = fts5IndexEntryCksum(iRowid, iCol, iPos, 0, pTerm, nTerm);
+
+  for(iIdx=0; iIdx<pConfig->nPrefix; iIdx++){
+    int nByte = fts5IndexCharlenToBytelen(pTerm, nTerm, pConfig->aPrefix[iIdx]);
+    if( nByte ){
+      ret ^= fts5IndexEntryCksum(iRowid, iCol, iPos, iIdx+1, pTerm, nByte);
+    }
+  }
+
+  return ret;
+}
+
+/*************************************************************************
+**************************************************************************
+** Below this point is the implementation of the fts5_decode() scalar
+** function only.
+*/
+
+/*
+** Decode a segment-data rowid from the %_data table. This function is
+** the opposite of macro FTS5_SEGMENT_ROWID().
+*/
+static void fts5DecodeRowid(
+  i64 iRowid,                     /* Rowid from %_data table */
+  int *piSegid,                   /* OUT: Segment id */
+  int *pbDlidx,                   /* OUT: Dlidx flag */
+  int *piHeight,                  /* OUT: Height */
+  int *piPgno                     /* OUT: Page number */
+){
+  *piPgno = (int)(iRowid & (((i64)1 << FTS5_DATA_PAGE_B) - 1));
+  iRowid >>= FTS5_DATA_PAGE_B;
+
+  *piHeight = (int)(iRowid & (((i64)1 << FTS5_DATA_HEIGHT_B) - 1));
+  iRowid >>= FTS5_DATA_HEIGHT_B;
+
+  *pbDlidx = (int)(iRowid & 0x0001);
+  iRowid >>= FTS5_DATA_DLI_B;
+
+  *piSegid = (int)(iRowid & (((i64)1 << FTS5_DATA_ID_B) - 1));
+}
+
+static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){
+  int iSegid, iHeight, iPgno, bDlidx;       /* Rowid compenents */
+  fts5DecodeRowid(iKey, &iSegid, &bDlidx, &iHeight, &iPgno);
+
+  if( iSegid==0 ){
+    if( iKey==FTS5_AVERAGES_ROWID ){
+      sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{averages} ");
+    }else{
+      sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{structure}");
+    }
+  }
+  else{
+    sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{%ssegid=%d h=%d pgno=%d}",
+        bDlidx ? "dlidx " : "", iSegid, iHeight, iPgno
+    );
+  }
+}
+
+static void fts5DebugStructure(
+  int *pRc,                       /* IN/OUT: error code */
+  Fts5Buffer *pBuf,
+  Fts5Structure *p
+){
+  int iLvl, iSeg;                 /* Iterate through levels, segments */
+
+  for(iLvl=0; iLvl<p->nLevel; iLvl++){
+    Fts5StructureLevel *pLvl = &p->aLevel[iLvl];
+    sqlite3Fts5BufferAppendPrintf(pRc, pBuf, 
+        " {lvl=%d nMerge=%d nSeg=%d", iLvl, pLvl->nMerge, pLvl->nSeg
+    );
+    for(iSeg=0; iSeg<pLvl->nSeg; iSeg++){
+      Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg];
+      sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " {id=%d leaves=%d..%d}", 
+          pSeg->iSegid, pSeg->pgnoFirst, pSeg->pgnoLast
+      );
+    }
+    sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "}");
+  }
+}
+
+/*
+** This is part of the fts5_decode() debugging aid.
+**
+** Arguments pBlob/nBlob contain a serialized Fts5Structure object. This
+** function appends a human-readable representation of the same object
+** to the buffer passed as the second argument. 
+*/
+static void fts5DecodeStructure(
+  int *pRc,                       /* IN/OUT: error code */
+  Fts5Buffer *pBuf,
+  const u8 *pBlob, int nBlob
+){
+  int rc;                         /* Return code */
+  Fts5Structure *p = 0;           /* Decoded structure object */
+
+  rc = fts5StructureDecode(pBlob, nBlob, 0, &p);
+  if( rc!=SQLITE_OK ){
+    *pRc = rc;
+    return;
+  }
+
+  fts5DebugStructure(pRc, pBuf, p);
+  fts5StructureRelease(p);
+}
+
+/*
+** This is part of the fts5_decode() debugging aid.
+**
+** Arguments pBlob/nBlob contain an "averages" record. This function 
+** appends a human-readable representation of record to the buffer passed 
+** as the second argument. 
+*/
+static void fts5DecodeAverages(
+  int *pRc,                       /* IN/OUT: error code */
+  Fts5Buffer *pBuf,
+  const u8 *pBlob, int nBlob
+){
+  int i = 0;
+  const char *zSpace = "";
+
+  while( i<nBlob ){
+    u64 iVal;
+    i += sqlite3Fts5GetVarint(&pBlob[i], &iVal);
+    sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "%s%d", zSpace, (int)iVal);
+    zSpace = " ";
+  }
+}
+
+/*
+** Buffer (a/n) is assumed to contain a list of serialized varints. Read
+** each varint and append its string representation to buffer pBuf. Return
+** after either the input buffer is exhausted or a 0 value is read.
+**
+** The return value is the number of bytes read from the input buffer.
+*/
+static int fts5DecodePoslist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){
+  int iOff = 0;
+  while( iOff<n ){
+    int iVal;
+    iOff += fts5GetVarint32(&a[iOff], iVal);
+    sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %d", iVal);
+  }
+  return iOff;
+}
+
+/*
+** The start of buffer (a/n) contains the start of a doclist. The doclist
+** may or may not finish within the buffer. This function appends a text
+** representation of the part of the doclist that is present to buffer
+** pBuf. 
+**
+** The return value is the number of bytes read from the input buffer.
+*/
+static int fts5DecodeDoclist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){
+  i64 iDocid = 0;
+  int iOff = 0;
+
+  if( n>0 ){
+    iOff = sqlite3Fts5GetVarint(a, (u64*)&iDocid);
+    sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " id=%lld", iDocid);
+  }
+  while( iOff<n ){
+    int nPos;
+    int bDummy;
+    iOff += fts5GetPoslistSize(&a[iOff], &nPos, &bDummy);
+    iOff += fts5DecodePoslist(pRc, pBuf, &a[iOff], MIN(n-iOff, nPos));
+    if( iOff<n ){
+      i64 iDelta;
+      iOff += sqlite3Fts5GetVarint(&a[iOff], (u64*)&iDelta);
+      iDocid += iDelta;
+      sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " id=%lld", iDocid);
+    }
+  }
+
+  return iOff;
+}
+
+/*
+** The implementation of user-defined scalar function fts5_decode().
+*/
+static void fts5DecodeFunction(
+  sqlite3_context *pCtx,          /* Function call context */
+  int nArg,                       /* Number of args (always 2) */
+  sqlite3_value **apVal           /* Function arguments */
+){
+  i64 iRowid;                     /* Rowid for record being decoded */
+  int iSegid,iHeight,iPgno,bDlidx;/* Rowid components */
+  const u8 *aBlob; int n;         /* Record to decode */
+  u8 *a = 0;
+  Fts5Buffer s;                   /* Build up text to return here */
+  int rc = SQLITE_OK;             /* Return code */
+  int nSpace = 0;
+
+  assert( nArg==2 );
+  memset(&s, 0, sizeof(Fts5Buffer));
+  iRowid = sqlite3_value_int64(apVal[0]);
+
+  /* Make a copy of the second argument (a blob) in aBlob[]. The aBlob[]
+  ** copy is followed by FTS5_DATA_ZERO_PADDING 0x00 bytes, which prevents
+  ** buffer overreads even if the record is corrupt.  */
+  n = sqlite3_value_bytes(apVal[1]);
+  aBlob = sqlite3_value_blob(apVal[1]);
+  nSpace = n + FTS5_DATA_ZERO_PADDING;
+  a = (u8*)sqlite3Fts5MallocZero(&rc, nSpace);
+  if( a==0 ) goto decode_out;
+  memcpy(a, aBlob, n);
+
+
+  fts5DecodeRowid(iRowid, &iSegid, &bDlidx, &iHeight, &iPgno);
+
+  fts5DebugRowid(&rc, &s, iRowid);
+  if( bDlidx ){
+    Fts5Data dlidx;
+    Fts5DlidxLvl lvl;
+
+    dlidx.p = a;
+    dlidx.nn = n;
+
+    memset(&lvl, 0, sizeof(Fts5DlidxLvl));
+    lvl.pData = &dlidx;
+    lvl.iLeafPgno = iPgno;
+
+    for(fts5DlidxLvlNext(&lvl); lvl.bEof==0; fts5DlidxLvlNext(&lvl)){
+      sqlite3Fts5BufferAppendPrintf(&rc, &s, 
+          " %d(%lld)", lvl.iLeafPgno, lvl.iRowid
+      );
+    }
+  }else if( iSegid==0 ){
+    if( iRowid==FTS5_AVERAGES_ROWID ){
+      fts5DecodeAverages(&rc, &s, a, n);
+    }else{
+      fts5DecodeStructure(&rc, &s, a, n);
+    }
+  }else{
+    Fts5Buffer term;              /* Current term read from page */
+    int szLeaf;                   /* Offset of pgidx in a[] */
+    int iPgidxOff;
+    int iPgidxPrev = 0;           /* Previous value read from pgidx */
+    int iTermOff = 0;
+    int iRowidOff = 0;
+    int iOff;
+    int nDoclist;
+
+    memset(&term, 0, sizeof(Fts5Buffer));
+
+    if( n<4 ){
+      sqlite3Fts5BufferSet(&rc, &s, 7, (const u8*)"corrupt");
+      goto decode_out;
+    }else{
+      iRowidOff = fts5GetU16(&a[0]);
+      iPgidxOff = szLeaf = fts5GetU16(&a[2]);
+      if( iPgidxOff<n ){
+        fts5GetVarint32(&a[iPgidxOff], iTermOff);
+      }
+    }
+
+    /* Decode the position list tail at the start of the page */
+    if( iRowidOff!=0 ){
+      iOff = iRowidOff;
+    }else if( iTermOff!=0 ){
+      iOff = iTermOff;
+    }else{
+      iOff = szLeaf;
+    }
+    fts5DecodePoslist(&rc, &s, &a[4], iOff-4);
+
+    /* Decode any more doclist data that appears on the page before the
+    ** first term. */
+    nDoclist = (iTermOff ? iTermOff : szLeaf) - iOff;
+    fts5DecodeDoclist(&rc, &s, &a[iOff], nDoclist);
+
+    while( iPgidxOff<n ){
+      int bFirst = (iPgidxOff==szLeaf);     /* True for first term on page */
+      int nByte;                            /* Bytes of data */
+      int iEnd;
+      
+      iPgidxOff += fts5GetVarint32(&a[iPgidxOff], nByte);
+      iPgidxPrev += nByte;
+      iOff = iPgidxPrev;
+
+      if( iPgidxOff<n ){
+        fts5GetVarint32(&a[iPgidxOff], nByte);
+        iEnd = iPgidxPrev + nByte;
+      }else{
+        iEnd = szLeaf;
+      }
+
+      if( bFirst==0 ){
+        iOff += fts5GetVarint32(&a[iOff], nByte);
+        term.n = nByte;
+      }
+      iOff += fts5GetVarint32(&a[iOff], nByte);
+      fts5BufferAppendBlob(&rc, &term, nByte, &a[iOff]);
+      iOff += nByte;
+
+      sqlite3Fts5BufferAppendPrintf(
+          &rc, &s, " term=%.*s", term.n, (const char*)term.p
+      );
+      iOff += fts5DecodeDoclist(&rc, &s, &a[iOff], iEnd-iOff);
+    }
+
+    fts5BufferFree(&term);
+  }
+  
+ decode_out:
+  sqlite3_free(a);
+  if( rc==SQLITE_OK ){
+    sqlite3_result_text(pCtx, (const char*)s.p, s.n, SQLITE_TRANSIENT);
+  }else{
+    sqlite3_result_error_code(pCtx, rc);
+  }
+  fts5BufferFree(&s);
+}
+
+/*
+** The implementation of user-defined scalar function fts5_rowid().
+*/
+static void fts5RowidFunction(
+  sqlite3_context *pCtx,          /* Function call context */
+  int nArg,                       /* Number of args (always 2) */
+  sqlite3_value **apVal           /* Function arguments */
+){
+  const char *zArg;
+  if( nArg==0 ){
+    sqlite3_result_error(pCtx, "should be: fts5_rowid(subject, ....)", -1);
+  }else{
+    zArg = (const char*)sqlite3_value_text(apVal[0]);
+    if( 0==sqlite3_stricmp(zArg, "segment") ){
+      i64 iRowid;
+      int segid, pgno;
+      if( nArg!=3 ){
+        sqlite3_result_error(pCtx, 
+            "should be: fts5_rowid('segment', segid, pgno))", -1
+        );
+      }else{
+        segid = sqlite3_value_int(apVal[1]);
+        pgno = sqlite3_value_int(apVal[2]);
+        iRowid = FTS5_SEGMENT_ROWID(segid, pgno);
+        sqlite3_result_int64(pCtx, iRowid);
+      }
+    }else{
+      sqlite3_result_error(pCtx, 
+        "first arg to fts5_rowid() must be 'segment'" , -1
+      );
+    }
+  }
+}
+
+/*
+** This is called as part of registering the FTS5 module with database
+** connection db. It registers several user-defined scalar functions useful
+** with FTS5.
+**
+** If successful, SQLITE_OK is returned. If an error occurs, some other
+** SQLite error code is returned instead.
+*/
+static int sqlite3Fts5IndexInit(sqlite3 *db){
+  int rc = sqlite3_create_function(
+      db, "fts5_decode", 2, SQLITE_UTF8, 0, fts5DecodeFunction, 0, 0
+  );
+  if( rc==SQLITE_OK ){
+    rc = sqlite3_create_function(
+        db, "fts5_rowid", -1, SQLITE_UTF8, 0, fts5RowidFunction, 0, 0
+    );
+  }
+  return rc;
+}
+
+
+/*
+** 2014 Jun 09
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This is an SQLite module implementing full-text search.
+*/
+
+
+
+/*
+** This variable is set to false when running tests for which the on disk
+** structures should not be corrupt. Otherwise, true. If it is false, extra
+** assert() conditions in the fts5 code are activated - conditions that are
+** only true if it is guaranteed that the fts5 database is not corrupt.
+*/
+SQLITE_API int sqlite3_fts5_may_be_corrupt = 1;
+
+
+typedef struct Fts5Auxdata Fts5Auxdata;
+typedef struct Fts5Auxiliary Fts5Auxiliary;
+typedef struct Fts5Cursor Fts5Cursor;
+typedef struct Fts5Sorter Fts5Sorter;
+typedef struct Fts5Table Fts5Table;
+typedef struct Fts5TokenizerModule Fts5TokenizerModule;
+
+/*
+** NOTES ON TRANSACTIONS: 
+**
+** SQLite invokes the following virtual table methods as transactions are 
+** opened and closed by the user:
+**
+**     xBegin():    Start of a new transaction.
+**     xSync():     Initial part of two-phase commit.
+**     xCommit():   Final part of two-phase commit.
+**     xRollback(): Rollback the transaction.
+**
+** Anything that is required as part of a commit that may fail is performed
+** in the xSync() callback. Current versions of SQLite ignore any errors 
+** returned by xCommit().
+**
+** And as sub-transactions are opened/closed:
+**
+**     xSavepoint(int S):  Open savepoint S.
+**     xRelease(int S):    Commit and close savepoint S.
+**     xRollbackTo(int S): Rollback to start of savepoint S.
+**
+** During a write-transaction the fts5_index.c module may cache some data 
+** in-memory. It is flushed to disk whenever xSync(), xRelease() or
+** xSavepoint() is called. And discarded whenever xRollback() or xRollbackTo() 
+** is called.
+**
+** Additionally, if SQLITE_DEBUG is defined, an instance of the following
+** structure is used to record the current transaction state. This information
+** is not required, but it is used in the assert() statements executed by
+** function fts5CheckTransactionState() (see below).
+*/
+struct Fts5TransactionState {
+  int eState;                     /* 0==closed, 1==open, 2==synced */
+  int iSavepoint;                 /* Number of open savepoints (0 -> none) */
+};
+
+/*
+** A single object of this type is allocated when the FTS5 module is 
+** registered with a database handle. It is used to store pointers to
+** all registered FTS5 extensions - tokenizers and auxiliary functions.
+*/
+struct Fts5Global {
+  fts5_api api;                   /* User visible part of object (see fts5.h) */
+  sqlite3 *db;                    /* Associated database connection */ 
+  i64 iNextId;                    /* Used to allocate unique cursor ids */
+  Fts5Auxiliary *pAux;            /* First in list of all aux. functions */
+  Fts5TokenizerModule *pTok;      /* First in list of all tokenizer modules */
+  Fts5TokenizerModule *pDfltTok;  /* Default tokenizer module */
+  Fts5Cursor *pCsr;               /* First in list of all open cursors */
+};
+
+/*
+** Each auxiliary function registered with the FTS5 module is represented
+** by an object of the following type. All such objects are stored as part
+** of the Fts5Global.pAux list.
+*/
+struct Fts5Auxiliary {
+  Fts5Global *pGlobal;            /* Global context for this function */
+  char *zFunc;                    /* Function name (nul-terminated) */
+  void *pUserData;                /* User-data pointer */
+  fts5_extension_function xFunc;  /* Callback function */
+  void (*xDestroy)(void*);        /* Destructor function */
+  Fts5Auxiliary *pNext;           /* Next registered auxiliary function */
+};
+
+/*
+** Each tokenizer module registered with the FTS5 module is represented
+** by an object of the following type. All such objects are stored as part
+** of the Fts5Global.pTok list.
+*/
+struct Fts5TokenizerModule {
+  char *zName;                    /* Name of tokenizer */
+  void *pUserData;                /* User pointer passed to xCreate() */
+  fts5_tokenizer x;               /* Tokenizer functions */
+  void (*xDestroy)(void*);        /* Destructor function */
+  Fts5TokenizerModule *pNext;     /* Next registered tokenizer module */
+};
+
+/*
+** Virtual-table object.
+*/
+struct Fts5Table {
+  sqlite3_vtab base;              /* Base class used by SQLite core */
+  Fts5Config *pConfig;            /* Virtual table configuration */
+  Fts5Index *pIndex;              /* Full-text index */
+  Fts5Storage *pStorage;          /* Document store */
+  Fts5Global *pGlobal;            /* Global (connection wide) data */
+  Fts5Cursor *pSortCsr;           /* Sort data from this cursor */
+#ifdef SQLITE_DEBUG
+  struct Fts5TransactionState ts;
+#endif
+};
+
+struct Fts5MatchPhrase {
+  Fts5Buffer *pPoslist;           /* Pointer to current poslist */
+  int nTerm;                      /* Size of phrase in terms */
+};
+
+/*
+** pStmt:
+**   SELECT rowid, <fts> FROM <fts> ORDER BY +rank;
+**
+** aIdx[]:
+**   There is one entry in the aIdx[] array for each phrase in the query,
+**   the value of which is the offset within aPoslist[] following the last 
+**   byte of the position list for the corresponding phrase.
+*/
+struct Fts5Sorter {
+  sqlite3_stmt *pStmt;
+  i64 iRowid;                     /* Current rowid */
+  const u8 *aPoslist;             /* Position lists for current row */
+  int nIdx;                       /* Number of entries in aIdx[] */
+  int aIdx[1];                    /* Offsets into aPoslist for current row */
+};
+
+
+/*
+** Virtual-table cursor object.
+**
+** iSpecial:
+**   If this is a 'special' query (refer to function fts5SpecialMatch()), 
+**   then this variable contains the result of the query. 
+**
+** iFirstRowid, iLastRowid:
+**   These variables are only used for FTS5_PLAN_MATCH cursors. Assuming the
+**   cursor iterates in ascending order of rowids, iFirstRowid is the lower
+**   limit of rowids to return, and iLastRowid the upper. In other words, the
+**   WHERE clause in the user's query might have been:
+**
+**       <tbl> MATCH <expr> AND rowid BETWEEN $iFirstRowid AND $iLastRowid
+**
+**   If the cursor iterates in descending order of rowid, iFirstRowid
+**   is the upper limit (i.e. the "first" rowid visited) and iLastRowid
+**   the lower.
+*/
+struct Fts5Cursor {
+  sqlite3_vtab_cursor base;       /* Base class used by SQLite core */
+  Fts5Cursor *pNext;              /* Next cursor in Fts5Cursor.pCsr list */
+  int *aColumnSize;               /* Values for xColumnSize() */
+  i64 iCsrId;                     /* Cursor id */
+
+  /* Zero from this point onwards on cursor reset */
+  int ePlan;                      /* FTS5_PLAN_XXX value */
+  int bDesc;                      /* True for "ORDER BY rowid DESC" queries */
+  i64 iFirstRowid;                /* Return no rowids earlier than this */
+  i64 iLastRowid;                 /* Return no rowids later than this */
+  sqlite3_stmt *pStmt;            /* Statement used to read %_content */
+  Fts5Expr *pExpr;                /* Expression for MATCH queries */
+  Fts5Sorter *pSorter;            /* Sorter for "ORDER BY rank" queries */
+  int csrflags;                   /* Mask of cursor flags (see below) */
+  i64 iSpecial;                   /* Result of special query */
+
+  /* "rank" function. Populated on demand from vtab.xColumn(). */
+  char *zRank;                    /* Custom rank function */
+  char *zRankArgs;                /* Custom rank function args */
+  Fts5Auxiliary *pRank;           /* Rank callback (or NULL) */
+  int nRankArg;                   /* Number of trailing arguments for rank() */
+  sqlite3_value **apRankArg;      /* Array of trailing arguments */
+  sqlite3_stmt *pRankArgStmt;     /* Origin of objects in apRankArg[] */
+
+  /* Auxiliary data storage */
+  Fts5Auxiliary *pAux;            /* Currently executing extension function */
+  Fts5Auxdata *pAuxdata;          /* First in linked list of saved aux-data */
+
+  /* Cache used by auxiliary functions xInst() and xInstCount() */
+  Fts5PoslistReader *aInstIter;   /* One for each phrase */
+  int nInstAlloc;                 /* Size of aInst[] array (entries / 3) */
+  int nInstCount;                 /* Number of phrase instances */
+  int *aInst;                     /* 3 integers per phrase instance */
+};
+
+/*
+** Bits that make up the "idxNum" parameter passed indirectly by 
+** xBestIndex() to xFilter().
+*/
+#define FTS5_BI_MATCH        0x0001         /* <tbl> MATCH ? */
+#define FTS5_BI_RANK         0x0002         /* rank MATCH ? */
+#define FTS5_BI_ROWID_EQ     0x0004         /* rowid == ? */
+#define FTS5_BI_ROWID_LE     0x0008         /* rowid <= ? */
+#define FTS5_BI_ROWID_GE     0x0010         /* rowid >= ? */
+
+#define FTS5_BI_ORDER_RANK   0x0020
+#define FTS5_BI_ORDER_ROWID  0x0040
+#define FTS5_BI_ORDER_DESC   0x0080
+
+/*
+** Values for Fts5Cursor.csrflags
+*/
+#define FTS5CSR_REQUIRE_CONTENT   0x01
+#define FTS5CSR_REQUIRE_DOCSIZE   0x02
+#define FTS5CSR_REQUIRE_INST      0x04
+#define FTS5CSR_EOF               0x08
+#define FTS5CSR_FREE_ZRANK        0x10
+#define FTS5CSR_REQUIRE_RESEEK    0x20
+
+#define BitFlagAllTest(x,y) (((x) & (y))==(y))
+#define BitFlagTest(x,y)    (((x) & (y))!=0)
+
+
+/*
+** Macros to Set(), Clear() and Test() cursor flags.
+*/
+#define CsrFlagSet(pCsr, flag)   ((pCsr)->csrflags |= (flag))
+#define CsrFlagClear(pCsr, flag) ((pCsr)->csrflags &= ~(flag))
+#define CsrFlagTest(pCsr, flag)  ((pCsr)->csrflags & (flag))
+
+struct Fts5Auxdata {
+  Fts5Auxiliary *pAux;            /* Extension to which this belongs */
+  void *pPtr;                     /* Pointer value */
+  void(*xDelete)(void*);          /* Destructor */
+  Fts5Auxdata *pNext;             /* Next object in linked list */
+};
+
+#ifdef SQLITE_DEBUG
+#define FTS5_BEGIN      1
+#define FTS5_SYNC       2
+#define FTS5_COMMIT     3
+#define FTS5_ROLLBACK   4
+#define FTS5_SAVEPOINT  5
+#define FTS5_RELEASE    6
+#define FTS5_ROLLBACKTO 7
+static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){
+  switch( op ){
+    case FTS5_BEGIN:
+      assert( p->ts.eState==0 );
+      p->ts.eState = 1;
+      p->ts.iSavepoint = -1;
+      break;
+
+    case FTS5_SYNC:
+      assert( p->ts.eState==1 );
+      p->ts.eState = 2;
+      break;
+
+    case FTS5_COMMIT:
+      assert( p->ts.eState==2 );
+      p->ts.eState = 0;
+      break;
+
+    case FTS5_ROLLBACK:
+      assert( p->ts.eState==1 || p->ts.eState==2 || p->ts.eState==0 );
+      p->ts.eState = 0;
+      break;
+
+    case FTS5_SAVEPOINT:
+      assert( p->ts.eState==1 );
+      assert( iSavepoint>=0 );
+      assert( iSavepoint>p->ts.iSavepoint );
+      p->ts.iSavepoint = iSavepoint;
+      break;
+      
+    case FTS5_RELEASE:
+      assert( p->ts.eState==1 );
+      assert( iSavepoint>=0 );
+      assert( iSavepoint<=p->ts.iSavepoint );
+      p->ts.iSavepoint = iSavepoint-1;
+      break;
+
+    case FTS5_ROLLBACKTO:
+      assert( p->ts.eState==1 );
+      assert( iSavepoint>=0 );
+      assert( iSavepoint<=p->ts.iSavepoint );
+      p->ts.iSavepoint = iSavepoint;
+      break;
+  }
+}
+#else
+# define fts5CheckTransactionState(x,y,z)
+#endif
+
+/*
+** Return true if pTab is a contentless table.
+*/
+static int fts5IsContentless(Fts5Table *pTab){
+  return pTab->pConfig->eContent==FTS5_CONTENT_NONE;
+}
+
+/*
+** Delete a virtual table handle allocated by fts5InitVtab(). 
+*/
+static void fts5FreeVtab(Fts5Table *pTab){
+  if( pTab ){
+    sqlite3Fts5IndexClose(pTab->pIndex);
+    sqlite3Fts5StorageClose(pTab->pStorage);
+    sqlite3Fts5ConfigFree(pTab->pConfig);
+    sqlite3_free(pTab);
+  }
+}
+
+/*
+** The xDisconnect() virtual table method.
+*/
+static int fts5DisconnectMethod(sqlite3_vtab *pVtab){
+  fts5FreeVtab((Fts5Table*)pVtab);
+  return SQLITE_OK;
+}
+
+/*
+** The xDestroy() virtual table method.
+*/
+static int fts5DestroyMethod(sqlite3_vtab *pVtab){
+  Fts5Table *pTab = (Fts5Table*)pVtab;
+  int rc = sqlite3Fts5DropAll(pTab->pConfig);
+  if( rc==SQLITE_OK ){
+    fts5FreeVtab((Fts5Table*)pVtab);
+  }
+  return rc;
+}
+
+/*
+** This function is the implementation of both the xConnect and xCreate
+** methods of the FTS3 virtual table.
+**
+** The argv[] array contains the following:
+**
+**   argv[0]   -> module name  ("fts5")
+**   argv[1]   -> database name
+**   argv[2]   -> table name
+**   argv[...] -> "column name" and other module argument fields.
+*/
+static int fts5InitVtab(
+  int bCreate,                    /* True for xCreate, false for xConnect */
+  sqlite3 *db,                    /* The SQLite database connection */
+  void *pAux,                     /* Hash table containing tokenizers */
+  int argc,                       /* Number of elements in argv array */
+  const char * const *argv,       /* xCreate/xConnect argument array */
+  sqlite3_vtab **ppVTab,          /* Write the resulting vtab structure here */
+  char **pzErr                    /* Write any error message here */
+){
+  Fts5Global *pGlobal = (Fts5Global*)pAux;
+  const char **azConfig = (const char**)argv;
+  int rc = SQLITE_OK;             /* Return code */
+  Fts5Config *pConfig = 0;        /* Results of parsing argc/argv */
+  Fts5Table *pTab = 0;            /* New virtual table object */
+
+  /* Allocate the new vtab object and parse the configuration */
+  pTab = (Fts5Table*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Table));
+  if( rc==SQLITE_OK ){
+    rc = sqlite3Fts5ConfigParse(pGlobal, db, argc, azConfig, &pConfig, pzErr);
+    assert( (rc==SQLITE_OK && *pzErr==0) || pConfig==0 );
+  }
+  if( rc==SQLITE_OK ){
+    pTab->pConfig = pConfig;
+    pTab->pGlobal = pGlobal;
+  }
+
+  /* Open the index sub-system */
+  if( rc==SQLITE_OK ){
+    rc = sqlite3Fts5IndexOpen(pConfig, bCreate, &pTab->pIndex, pzErr);
+  }
+
+  /* Open the storage sub-system */
+  if( rc==SQLITE_OK ){
+    rc = sqlite3Fts5StorageOpen(
+        pConfig, pTab->pIndex, bCreate, &pTab->pStorage, pzErr
+    );
+  }
+
+  /* Call sqlite3_declare_vtab() */
+  if( rc==SQLITE_OK ){
+    rc = sqlite3Fts5ConfigDeclareVtab(pConfig);
+  }
+
+  if( rc!=SQLITE_OK ){
+    fts5FreeVtab(pTab);
+    pTab = 0;
+  }else if( bCreate ){
+    fts5CheckTransactionState(pTab, FTS5_BEGIN, 0);
+  }
+  *ppVTab = (sqlite3_vtab*)pTab;
+  return rc;
+}
+
+/*
+** The xConnect() and xCreate() methods for the virtual table. All the
+** work is done in function fts5InitVtab().
+*/
+static int fts5ConnectMethod(
+  sqlite3 *db,                    /* Database connection */
+  void *pAux,                     /* Pointer to tokenizer hash table */
+  int argc,                       /* Number of elements in argv array */
+  const char * const *argv,       /* xCreate/xConnect argument array */
+  sqlite3_vtab **ppVtab,          /* OUT: New sqlite3_vtab object */
+  char **pzErr                    /* OUT: sqlite3_malloc'd error message */
+){
+  return fts5InitVtab(0, db, pAux, argc, argv, ppVtab, pzErr);
+}
+static int fts5CreateMethod(
+  sqlite3 *db,                    /* Database connection */
+  void *pAux,                     /* Pointer to tokenizer hash table */
+  int argc,                       /* Number of elements in argv array */
+  const char * const *argv,       /* xCreate/xConnect argument array */
+  sqlite3_vtab **ppVtab,          /* OUT: New sqlite3_vtab object */
+  char **pzErr                    /* OUT: sqlite3_malloc'd error message */
+){
+  return fts5InitVtab(1, db, pAux, argc, argv, ppVtab, pzErr);
+}
+
+/*
+** The different query plans.
+*/
+#define FTS5_PLAN_MATCH          1       /* (<tbl> MATCH ?) */
+#define FTS5_PLAN_SOURCE         2       /* A source cursor for SORTED_MATCH */
+#define FTS5_PLAN_SPECIAL        3       /* An internal query */
+#define FTS5_PLAN_SORTED_MATCH   4       /* (<tbl> MATCH ? ORDER BY rank) */
+#define FTS5_PLAN_SCAN           5       /* No usable constraint */
+#define FTS5_PLAN_ROWID          6       /* (rowid = ?) */
+
+/*
+** Set the SQLITE_INDEX_SCAN_UNIQUE flag in pIdxInfo->flags. Unless this
+** extension is currently being used by a version of SQLite too old to
+** support index-info flags. In that case this function is a no-op.
+*/
+static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
+#if SQLITE_VERSION_NUMBER>=3008012
+  if( sqlite3_libversion_number()>=3008012 ){
+    pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE;
+  }
+#endif
+}
+
+/*
+** Implementation of the xBestIndex method for FTS5 tables. Within the 
+** WHERE constraint, it searches for the following:
+**
+**   1. A MATCH constraint against the special column.
+**   2. A MATCH constraint against the "rank" column.
+**   3. An == constraint against the rowid column.
+**   4. A < or <= constraint against the rowid column.
+**   5. A > or >= constraint against the rowid column.
+**
+** Within the ORDER BY, either:
+**
+**   5. ORDER BY rank [ASC|DESC]
+**   6. ORDER BY rowid [ASC|DESC]
+**
+** Costs are assigned as follows:
+**
+**  a) If an unusable MATCH operator is present in the WHERE clause, the
+**     cost is unconditionally set to 1e50 (a really big number).
+**
+**  a) If a MATCH operator is present, the cost depends on the other
+**     constraints also present. As follows:
+**
+**       * No other constraints:         cost=1000.0
+**       * One rowid range constraint:   cost=750.0
+**       * Both rowid range constraints: cost=500.0
+**       * An == rowid constraint:       cost=100.0
+**
+**  b) Otherwise, if there is no MATCH:
+**
+**       * No other constraints:         cost=1000000.0
+**       * One rowid range constraint:   cost=750000.0
+**       * Both rowid range constraints: cost=250000.0
+**       * An == rowid constraint:       cost=10.0
+**
+** Costs are not modified by the ORDER BY clause.
+*/
+static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
+  Fts5Table *pTab = (Fts5Table*)pVTab;
+  Fts5Config *pConfig = pTab->pConfig;
+  int idxFlags = 0;               /* Parameter passed through to xFilter() */
+  int bHasMatch;
+  int iNext;
+  int i;
+
+  struct Constraint {
+    int op;                       /* Mask against sqlite3_index_constraint.op */
+    int fts5op;                   /* FTS5 mask for idxFlags */
+    int iCol;                     /* 0==rowid, 1==tbl, 2==rank */
+    int omit;                     /* True to omit this if found */
+    int iConsIndex;               /* Index in pInfo->aConstraint[] */
+  } aConstraint[] = {
+    {SQLITE_INDEX_CONSTRAINT_MATCH|SQLITE_INDEX_CONSTRAINT_EQ, 
+                                    FTS5_BI_MATCH,    1, 1, -1},
+    {SQLITE_INDEX_CONSTRAINT_MATCH|SQLITE_INDEX_CONSTRAINT_EQ, 
+                                    FTS5_BI_RANK,     2, 1, -1},
+    {SQLITE_INDEX_CONSTRAINT_EQ,    FTS5_BI_ROWID_EQ, 0, 0, -1},
+    {SQLITE_INDEX_CONSTRAINT_LT|SQLITE_INDEX_CONSTRAINT_LE, 
+                                    FTS5_BI_ROWID_LE, 0, 0, -1},
+    {SQLITE_INDEX_CONSTRAINT_GT|SQLITE_INDEX_CONSTRAINT_GE, 
+                                    FTS5_BI_ROWID_GE, 0, 0, -1},
+  };
+
+  int aColMap[3];
+  aColMap[0] = -1;
+  aColMap[1] = pConfig->nCol;
+  aColMap[2] = pConfig->nCol+1;
+
+  /* Set idxFlags flags for all WHERE clause terms that will be used. */
+  for(i=0; i<pInfo->nConstraint; i++){
+    struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
+    int j;
+    for(j=0; j<sizeof(aConstraint)/sizeof(aConstraint[0]); j++){
+      struct Constraint *pC = &aConstraint[j];
+      if( p->iColumn==aColMap[pC->iCol] && p->op & pC->op ){
+        if( p->usable ){
+          pC->iConsIndex = i;
+          idxFlags |= pC->fts5op;
+        }else if( j==0 ){
+          /* As there exists an unusable MATCH constraint this is an 
+          ** unusable plan. Set a prohibitively high cost. */
+          pInfo->estimatedCost = 1e50;
+          return SQLITE_OK;
+        }
+      }
+    }
+  }
+
+  /* Set idxFlags flags for the ORDER BY clause */
+  if( pInfo->nOrderBy==1 ){
+    int iSort = pInfo->aOrderBy[0].iColumn;
+    if( iSort==(pConfig->nCol+1) && BitFlagTest(idxFlags, FTS5_BI_MATCH) ){
+      idxFlags |= FTS5_BI_ORDER_RANK;
+    }else if( iSort==-1 ){
+      idxFlags |= FTS5_BI_ORDER_ROWID;
+    }
+    if( BitFlagTest(idxFlags, FTS5_BI_ORDER_RANK|FTS5_BI_ORDER_ROWID) ){
+      pInfo->orderByConsumed = 1;
+      if( pInfo->aOrderBy[0].desc ){
+        idxFlags |= FTS5_BI_ORDER_DESC;
+      }
+    }
+  }
+
+  /* Calculate the estimated cost based on the flags set in idxFlags. */
+  bHasMatch = BitFlagTest(idxFlags, FTS5_BI_MATCH);
+  if( BitFlagTest(idxFlags, FTS5_BI_ROWID_EQ) ){
+    pInfo->estimatedCost = bHasMatch ? 100.0 : 10.0;
+    if( bHasMatch==0 ) fts5SetUniqueFlag(pInfo);
+  }else if( BitFlagAllTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){
+    pInfo->estimatedCost = bHasMatch ? 500.0 : 250000.0;
+  }else if( BitFlagTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){
+    pInfo->estimatedCost = bHasMatch ? 750.0 : 750000.0;
+  }else{
+    pInfo->estimatedCost = bHasMatch ? 1000.0 : 1000000.0;
+  }
+
+  /* Assign argvIndex values to each constraint in use. */
+  iNext = 1;
+  for(i=0; i<sizeof(aConstraint)/sizeof(aConstraint[0]); i++){
+    struct Constraint *pC = &aConstraint[i];
+    if( pC->iConsIndex>=0 ){
+      pInfo->aConstraintUsage[pC->iConsIndex].argvIndex = iNext++;
+      pInfo->aConstraintUsage[pC->iConsIndex].omit = pC->omit;
+    }
+  }
+
+  pInfo->idxNum = idxFlags;
+  return SQLITE_OK;
+}
+
+/*
+** Implementation of xOpen method.
+*/
+static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
+  Fts5Table *pTab = (Fts5Table*)pVTab;
+  Fts5Config *pConfig = pTab->pConfig;
+  Fts5Cursor *pCsr;               /* New cursor object */
+  int nByte;                      /* Bytes of space to allocate */
+  int rc = SQLITE_OK;             /* Return code */
+
+  nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int);
+  pCsr = (Fts5Cursor*)sqlite3_malloc(nByte);
+  if( pCsr ){
+    Fts5Global *pGlobal = pTab->pGlobal;
+    memset(pCsr, 0, nByte);
+    pCsr->aColumnSize = (int*)&pCsr[1];
+    pCsr->pNext = pGlobal->pCsr;
+    pGlobal->pCsr = pCsr;
+    pCsr->iCsrId = ++pGlobal->iNextId;
+  }else{
+    rc = SQLITE_NOMEM;
+  }
+  *ppCsr = (sqlite3_vtab_cursor*)pCsr;
+  return rc;
+}
+
+static int fts5StmtType(Fts5Cursor *pCsr){
+  if( pCsr->ePlan==FTS5_PLAN_SCAN ){
+    return (pCsr->bDesc) ? FTS5_STMT_SCAN_DESC : FTS5_STMT_SCAN_ASC;
+  }
+  return FTS5_STMT_LOOKUP;
+}
+
+/*
+** This function is called after the cursor passed as the only argument
+** is moved to point at a different row. It clears all cached data 
+** specific to the previous row stored by the cursor object.
+*/
+static void fts5CsrNewrow(Fts5Cursor *pCsr){
+  CsrFlagSet(pCsr, 
+      FTS5CSR_REQUIRE_CONTENT 
+    | FTS5CSR_REQUIRE_DOCSIZE 
+    | FTS5CSR_REQUIRE_INST 
+  );
+}
+
+static void fts5FreeCursorComponents(Fts5Cursor *pCsr){
+  Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
+  Fts5Auxdata *pData;
+  Fts5Auxdata *pNext;
+
+  sqlite3_free(pCsr->aInstIter);
+  sqlite3_free(pCsr->aInst);
+  if( pCsr->pStmt ){
+    int eStmt = fts5StmtType(pCsr);
+    sqlite3Fts5StorageStmtRelease(pTab->pStorage, eStmt, pCsr->pStmt);
+  }
+  if( pCsr->pSorter ){
+    Fts5Sorter *pSorter = pCsr->pSorter;
+    sqlite3_finalize(pSorter->pStmt);
+    sqlite3_free(pSorter);
+  }
+
+  if( pCsr->ePlan!=FTS5_PLAN_SOURCE ){
+    sqlite3Fts5ExprFree(pCsr->pExpr);
+  }
+
+  for(pData=pCsr->pAuxdata; pData; pData=pNext){
+    pNext = pData->pNext;
+    if( pData->xDelete ) pData->xDelete(pData->pPtr);
+    sqlite3_free(pData);
+  }
+
+  sqlite3_finalize(pCsr->pRankArgStmt);
+  sqlite3_free(pCsr->apRankArg);
+
+  if( CsrFlagTest(pCsr, FTS5CSR_FREE_ZRANK) ){
+    sqlite3_free(pCsr->zRank);
+    sqlite3_free(pCsr->zRankArgs);
+  }
+
+  memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan - (u8*)pCsr));
+}
+
+
+/*
+** Close the cursor.  For additional information see the documentation
+** on the xClose method of the virtual table interface.
+*/
+static int fts5CloseMethod(sqlite3_vtab_cursor *pCursor){
+  if( pCursor ){
+    Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab);
+    Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
+    Fts5Cursor **pp;
+
+    fts5FreeCursorComponents(pCsr);
+    /* Remove the cursor from the Fts5Global.pCsr list */
+    for(pp=&pTab->pGlobal->pCsr; (*pp)!=pCsr; pp=&(*pp)->pNext);
+    *pp = pCsr->pNext;
+
+    sqlite3_free(pCsr);
+  }
+  return SQLITE_OK;
+}
+
+static int fts5SorterNext(Fts5Cursor *pCsr){
+  Fts5Sorter *pSorter = pCsr->pSorter;
+  int rc;
+
+  rc = sqlite3_step(pSorter->pStmt);
+  if( rc==SQLITE_DONE ){
+    rc = SQLITE_OK;
+    CsrFlagSet(pCsr, FTS5CSR_EOF);
+  }else if( rc==SQLITE_ROW ){
+    const u8 *a;
+    const u8 *aBlob;
+    int nBlob;
+    int i;
+    int iOff = 0;
+    rc = SQLITE_OK;
+
+    pSorter->iRowid = sqlite3_column_int64(pSorter->pStmt, 0);
+    nBlob = sqlite3_column_bytes(pSorter->pStmt, 1);
+    aBlob = a = sqlite3_column_blob(pSorter->pStmt, 1);
+
+    for(i=0; i<(pSorter->nIdx-1); i++){
+      int iVal;
+      a += fts5GetVarint32(a, iVal);
+      iOff += iVal;
+      pSorter->aIdx[i] = iOff;
+    }
+    pSorter->aIdx[i] = &aBlob[nBlob] - a;
+
+    pSorter->aPoslist = a;
+    fts5CsrNewrow(pCsr);
+  }
+
+  return rc;
+}
+
+
+/*
+** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors 
+** open on table pTab.
+*/
+static void fts5TripCursors(Fts5Table *pTab){
+  Fts5Cursor *pCsr;
+  for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
+    if( pCsr->ePlan==FTS5_PLAN_MATCH
+     && pCsr->base.pVtab==(sqlite3_vtab*)pTab 
+    ){
+      CsrFlagSet(pCsr, FTS5CSR_REQUIRE_RESEEK);
+    }
+  }
+}
+
+/*
+** If the REQUIRE_RESEEK flag is set on the cursor passed as the first
+** argument, close and reopen all Fts5IndexIter iterators that the cursor 
+** is using. Then attempt to move the cursor to a rowid equal to or laster
+** (in the cursors sort order - ASC or DESC) than the current rowid. 
+**
+** If the new rowid is not equal to the old, set output parameter *pbSkip
+** to 1 before returning. Otherwise, leave it unchanged.
+**
+** Return SQLITE_OK if successful or if no reseek was required, or an 
+** error code if an error occurred.
+*/
+static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
+  int rc = SQLITE_OK;
+  assert( *pbSkip==0 );
+  if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_RESEEK) ){
+    Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
+    int bDesc = pCsr->bDesc;
+    i64 iRowid = sqlite3Fts5ExprRowid(pCsr->pExpr);
+
+    rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->pIndex, iRowid, bDesc);
+    if( rc==SQLITE_OK && iRowid!=sqlite3Fts5ExprRowid(pCsr->pExpr) ){
+      *pbSkip = 1;
+    }
+
+    CsrFlagClear(pCsr, FTS5CSR_REQUIRE_RESEEK);
+    fts5CsrNewrow(pCsr);
+    if( sqlite3Fts5ExprEof(pCsr->pExpr) ){
+      CsrFlagSet(pCsr, FTS5CSR_EOF);
+    }
+  }
+  return rc;
+}
+
+
+/*
+** Advance the cursor to the next row in the table that matches the 
+** search criteria.
+**
+** Return SQLITE_OK if nothing goes wrong.  SQLITE_OK is returned
+** even if we reach end-of-file.  The fts5EofMethod() will be called
+** subsequently to determine whether or not an EOF was hit.
+*/
+static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
+  Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
+  int rc = SQLITE_OK;
+
+  assert( (pCsr->ePlan<3)==
+          (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE) 
+  );
+
+  if( pCsr->ePlan<3 ){
+    int bSkip = 0;
+    if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc;
+    rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid);
+    if( sqlite3Fts5ExprEof(pCsr->pExpr) ){
+      CsrFlagSet(pCsr, FTS5CSR_EOF);
+    }
+    fts5CsrNewrow(pCsr);
+  }else{
+    switch( pCsr->ePlan ){
+      case FTS5_PLAN_SPECIAL: {
+        CsrFlagSet(pCsr, FTS5CSR_EOF);
+        break;
+      }
+  
+      case FTS5_PLAN_SORTED_MATCH: {
+        rc = fts5SorterNext(pCsr);
+        break;
+      }
+  
+      default:
+        rc = sqlite3_step(pCsr->pStmt);
+        if( rc!=SQLITE_ROW ){
+          CsrFlagSet(pCsr, FTS5CSR_EOF);
+          rc = sqlite3_reset(pCsr->pStmt);
+        }else{
+          rc = SQLITE_OK;
+        }
+        break;
+    }
+  }
+  
+  return rc;
+}
+
+static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
+  Fts5Config *pConfig = pTab->pConfig;
+  Fts5Sorter *pSorter;
+  int nPhrase;
+  int nByte;
+  int rc = SQLITE_OK;
+  char *zSql;
+  const char *zRank = pCsr->zRank;
+  const char *zRankArgs = pCsr->zRankArgs;
+  
+  nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
+  nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1);
+  pSorter = (Fts5Sorter*)sqlite3_malloc(nByte);
+  if( pSorter==0 ) return SQLITE_NOMEM;
+  memset(pSorter, 0, nByte);
+  pSorter->nIdx = nPhrase;
+
+  /* TODO: It would be better to have some system for reusing statement
+  ** handles here, rather than preparing a new one for each query. But that
+  ** is not possible as SQLite reference counts the virtual table objects.
+  ** And since the statement required here reads from this very virtual 
+  ** table, saving it creates a circular reference.
+  **
+  ** If SQLite a built-in statement cache, this wouldn't be a problem. */
+  zSql = sqlite3Fts5Mprintf(&rc, 
+      "SELECT rowid, rank FROM %Q.%Q ORDER BY %s(%s%s%s) %s",
+      pConfig->zDb, pConfig->zName, zRank, pConfig->zName,
+      (zRankArgs ? ", " : ""),
+      (zRankArgs ? zRankArgs : ""),
+      bDesc ? "DESC" : "ASC"
+  );
+  if( zSql ){
+    rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pSorter->pStmt, 0);
+    sqlite3_free(zSql);
+  }
+
+  pCsr->pSorter = pSorter;
+  if( rc==SQLITE_OK ){
+    assert( pTab->pSortCsr==0 );
+    pTab->pSortCsr = pCsr;
+    rc = fts5SorterNext(pCsr);
+    pTab->pSortCsr = 0;
+  }
+
+  if( rc!=SQLITE_OK ){
+    sqlite3_finalize(pSorter->pStmt);
+    sqlite3_free(pSorter);
+    pCsr->pSorter = 0;
+  }
+
+  return rc;
+}
+
+static int fts5CursorFirst(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){
+  int rc;
+  Fts5Expr *pExpr = pCsr->pExpr;
+  rc = sqlite3Fts5ExprFirst(pExpr, pTab->pIndex, pCsr->iFirstRowid, bDesc);
+  if( sqlite3Fts5ExprEof(pExpr) ){
+    CsrFlagSet(pCsr, FTS5CSR_EOF);
+  }
+  fts5CsrNewrow(pCsr);
+  return rc;
+}
+
+/*
+** Process a "special" query. A special query is identified as one with a
+** MATCH expression that begins with a '*' character. The remainder of
+** the text passed to the MATCH operator are used as  the special query
+** parameters.
+*/
+static int fts5SpecialMatch(
+  Fts5Table *pTab, 
+  Fts5Cursor *pCsr, 
+  const char *zQuery
+){
+  int rc = SQLITE_OK;             /* Return code */
+  const char *z = zQuery;         /* Special query text */
+  int n;                          /* Number of bytes in text at z */
+
+  while( z[0]==' ' ) z++;
+  for(n=0; z[n] && z[n]!=' '; n++);
+
+  assert( pTab->base.zErrMsg==0 );
+  pCsr->ePlan = FTS5_PLAN_SPECIAL;
+
+  if( 0==sqlite3_strnicmp("reads", z, n) ){
+    pCsr->iSpecial = sqlite3Fts5IndexReads(pTab->pIndex);
+  }
+  else if( 0==sqlite3_strnicmp("id", z, n) ){
+    pCsr->iSpecial = pCsr->iCsrId;
+  }
+  else{
+    /* An unrecognized directive. Return an error message. */
+    pTab->base.zErrMsg = sqlite3_mprintf("unknown special query: %.*s", n, z);
+    rc = SQLITE_ERROR;
+  }
+
+  return rc;
+}
+
+/*
+** Search for an auxiliary function named zName that can be used with table
+** pTab. If one is found, return a pointer to the corresponding Fts5Auxiliary
+** structure. Otherwise, if no such function exists, return NULL.
+*/
+static Fts5Auxiliary *fts5FindAuxiliary(Fts5Table *pTab, const char *zName){
+  Fts5Auxiliary *pAux;
+
+  for(pAux=pTab->pGlobal->pAux; pAux; pAux=pAux->pNext){
+    if( sqlite3_stricmp(zName, pAux->zFunc)==0 ) return pAux;
+  }
+
+  /* No function of the specified name was found. Return 0. */
+  return 0;
+}
+
+
+static int fts5FindRankFunction(Fts5Cursor *pCsr){
+  Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
+  Fts5Config *pConfig = pTab->pConfig;
+  int rc = SQLITE_OK;
+  Fts5Auxiliary *pAux = 0;
+  const char *zRank = pCsr->zRank;
+  const char *zRankArgs = pCsr->zRankArgs;
+
+  if( zRankArgs ){
+    char *zSql = sqlite3Fts5Mprintf(&rc, "SELECT %s", zRankArgs);
+    if( zSql ){
+      sqlite3_stmt *pStmt = 0;
+      rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pStmt, 0);
+      sqlite3_free(zSql);
+      assert( rc==SQLITE_OK || pCsr->pRankArgStmt==0 );
+      if( rc==SQLITE_OK ){
+        if( SQLITE_ROW==sqlite3_step(pStmt) ){
+          int nByte;
+          pCsr->nRankArg = sqlite3_column_count(pStmt);
+          nByte = sizeof(sqlite3_value*)*pCsr->nRankArg;
+          pCsr->apRankArg = (sqlite3_value**)sqlite3Fts5MallocZero(&rc, nByte);
+          if( rc==SQLITE_OK ){
+            int i;
+            for(i=0; i<pCsr->nRankArg; i++){
+              pCsr->apRankArg[i] = sqlite3_column_value(pStmt, i);
+            }
+          }
+          pCsr->pRankArgStmt = pStmt;
+        }else{
+          rc = sqlite3_finalize(pStmt);
+          assert( rc!=SQLITE_OK );
+        }
+      }
+    }
+  }
+
+  if( rc==SQLITE_OK ){
+    pAux = fts5FindAuxiliary(pTab, zRank);
+    if( pAux==0 ){
+      assert( pTab->base.zErrMsg==0 );
+      pTab->base.zErrMsg = sqlite3_mprintf("no such function: %s", zRank);
+      rc = SQLITE_ERROR;
+    }
+  }
+
+  pCsr->pRank = pAux;
+  return rc;
+}
+
+
+static int fts5CursorParseRank(
+  Fts5Config *pConfig,
+  Fts5Cursor *pCsr, 
+  sqlite3_value *pRank
+){
+  int rc = SQLITE_OK;
+  if( pRank ){
+    const char *z = (const char*)sqlite3_value_text(pRank);
+    char *zRank = 0;
+    char *zRankArgs = 0;
+
+    if( z==0 ){
+      if( sqlite3_value_type(pRank)==SQLITE_NULL ) rc = SQLITE_ERROR;
+    }else{
+      rc = sqlite3Fts5ConfigParseRank(z, &zRank, &zRankArgs);
+    }
+    if( rc==SQLITE_OK ){
+      pCsr->zRank = zRank;
+      pCsr->zRankArgs = zRankArgs;
+      CsrFlagSet(pCsr, FTS5CSR_FREE_ZRANK);
+    }else if( rc==SQLITE_ERROR ){
+      pCsr->base.pVtab->zErrMsg = sqlite3_mprintf(
+          "parse error in rank function: %s", z
+      );
+    }
+  }else{
+    if( pConfig->zRank ){
+      pCsr->zRank = (char*)pConfig->zRank;
+      pCsr->zRankArgs = (char*)pConfig->zRankArgs;
+    }else{
+      pCsr->zRank = (char*)FTS5_DEFAULT_RANK;
+      pCsr->zRankArgs = 0;
+    }
+  }
+  return rc;
+}
+
+static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){
+  if( pVal ){
+    int eType = sqlite3_value_numeric_type(pVal);
+    if( eType==SQLITE_INTEGER ){
+      return sqlite3_value_int64(pVal);
+    }
+  }
+  return iDefault;
+}
+
+/*
+** This is the xFilter interface for the virtual table.  See
+** the virtual table xFilter method documentation for additional
+** information.
+** 
+** There are three possible query strategies:
+**
+**   1. Full-text search using a MATCH operator.
+**   2. A by-rowid lookup.
+**   3. A full-table scan.
+*/
+static int fts5FilterMethod(
+  sqlite3_vtab_cursor *pCursor,   /* The cursor used for this query */
+  int idxNum,                     /* Strategy index */
+  const char *idxStr,             /* Unused */
+  int nVal,                       /* Number of elements in apVal */
+  sqlite3_value **apVal           /* Arguments for the indexing scheme */
+){
+  Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab);
+  Fts5Config *pConfig = pTab->pConfig;
+  Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
+  int rc = SQLITE_OK;             /* Error code */
+  int iVal = 0;                   /* Counter for apVal[] */
+  int bDesc;                      /* True if ORDER BY [rank|rowid] DESC */
+  int bOrderByRank;               /* True if ORDER BY rank */
+  sqlite3_value *pMatch = 0;      /* <tbl> MATCH ? expression (or NULL) */
+  sqlite3_value *pRank = 0;       /* rank MATCH ? expression (or NULL) */
+  sqlite3_value *pRowidEq = 0;    /* rowid = ? expression (or NULL) */
+  sqlite3_value *pRowidLe = 0;    /* rowid <= ? expression (or NULL) */
+  sqlite3_value *pRowidGe = 0;    /* rowid >= ? expression (or NULL) */
+  char **pzErrmsg = pConfig->pzErrmsg;
+
+  if( pCsr->ePlan ){
+    fts5FreeCursorComponents(pCsr);
+    memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr));
+  }
+
+  assert( pCsr->pStmt==0 );
+  assert( pCsr->pExpr==0 );
+  assert( pCsr->csrflags==0 );
+  assert( pCsr->pRank==0 );
+  assert( pCsr->zRank==0 );
+  assert( pCsr->zRankArgs==0 );
+
+  assert( pzErrmsg==0 || pzErrmsg==&pTab->base.zErrMsg );
+  pConfig->pzErrmsg = &pTab->base.zErrMsg;
+
+  /* Decode the arguments passed through to this function.
+  **
+  ** Note: The following set of if(...) statements must be in the same
+  ** order as the corresponding entries in the struct at the top of
+  ** fts5BestIndexMethod().  */
+  if( BitFlagTest(idxNum, FTS5_BI_MATCH) ) pMatch = apVal[iVal++];
+  if( BitFlagTest(idxNum, FTS5_BI_RANK) ) pRank = apVal[iVal++];
+  if( BitFlagTest(idxNum, FTS5_BI_ROWID_EQ) ) pRowidEq = apVal[iVal++];
+  if( BitFlagTest(idxNum, FTS5_BI_ROWID_LE) ) pRowidLe = apVal[iVal++];
+  if( BitFlagTest(idxNum, FTS5_BI_ROWID_GE) ) pRowidGe = apVal[iVal++];
+  assert( iVal==nVal );
+  bOrderByRank = ((idxNum & FTS5_BI_ORDER_RANK) ? 1 : 0);
+  pCsr->bDesc = bDesc = ((idxNum & FTS5_BI_ORDER_DESC) ? 1 : 0);
+
+  /* Set the cursor upper and lower rowid limits. Only some strategies 
+  ** actually use them. This is ok, as the xBestIndex() method leaves the
+  ** sqlite3_index_constraint.omit flag clear for range constraints
+  ** on the rowid field.  */
+  if( pRowidEq ){
+    pRowidLe = pRowidGe = pRowidEq;
+  }
+  if( bDesc ){
+    pCsr->iFirstRowid = fts5GetRowidLimit(pRowidLe, LARGEST_INT64);
+    pCsr->iLastRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64);
+  }else{
+    pCsr->iLastRowid = fts5GetRowidLimit(pRowidLe, LARGEST_INT64);
+    pCsr->iFirstRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64);
+  }
+
+  if( pTab->pSortCsr ){
+    /* If pSortCsr is non-NULL, then this call is being made as part of 
+    ** processing for a "... MATCH <expr> ORDER BY rank" query (ePlan is
+    ** set to FTS5_PLAN_SORTED_MATCH). pSortCsr is the cursor that will
+    ** return results to the user for this query. The current cursor 
+    ** (pCursor) is used to execute the query issued by function 
+    ** fts5CursorFirstSorted() above.  */
+    assert( pRowidEq==0 && pRowidLe==0 && pRowidGe==0 && pRank==0 );
+    assert( nVal==0 && pMatch==0 && bOrderByRank==0 && bDesc==0 );
+    assert( pCsr->iLastRowid==LARGEST_INT64 );
+    assert( pCsr->iFirstRowid==SMALLEST_INT64 );
+    pCsr->ePlan = FTS5_PLAN_SOURCE;
+    pCsr->pExpr = pTab->pSortCsr->pExpr;
+    rc = fts5CursorFirst(pTab, pCsr, bDesc);
+  }else if( pMatch ){
+    const char *zExpr = (const char*)sqlite3_value_text(apVal[0]);
+    if( zExpr==0 ) zExpr = "";
+
+    rc = fts5CursorParseRank(pConfig, pCsr, pRank);
+    if( rc==SQLITE_OK ){
+      if( zExpr[0]=='*' ){
+        /* The user has issued a query of the form "MATCH '*...'". This
+        ** indicates that the MATCH expression is not a full text query,
+        ** but a request for an internal parameter.  */
+        rc = fts5SpecialMatch(pTab, pCsr, &zExpr[1]);
+      }else{
+        char **pzErr = &pTab->base.zErrMsg;
+        rc = sqlite3Fts5ExprNew(pConfig, zExpr, &pCsr->pExpr, pzErr);
+        if( rc==SQLITE_OK ){
+          if( bOrderByRank ){
+            pCsr->ePlan = FTS5_PLAN_SORTED_MATCH;
+            rc = fts5CursorFirstSorted(pTab, pCsr, bDesc);
+          }else{
+            pCsr->ePlan = FTS5_PLAN_MATCH;
+            rc = fts5CursorFirst(pTab, pCsr, bDesc);
+          }
+        }
+      }
+    }
+  }else if( pConfig->zContent==0 ){
+    *pConfig->pzErrmsg = sqlite3_mprintf(
+        "%s: table does not support scanning", pConfig->zName
+    );
+    rc = SQLITE_ERROR;
+  }else{
+    /* This is either a full-table scan (ePlan==FTS5_PLAN_SCAN) or a lookup
+    ** by rowid (ePlan==FTS5_PLAN_ROWID).  */
+    pCsr->ePlan = (pRowidEq ? FTS5_PLAN_ROWID : FTS5_PLAN_SCAN);
+    rc = sqlite3Fts5StorageStmt(
+        pTab->pStorage, fts5StmtType(pCsr), &pCsr->pStmt, &pTab->base.zErrMsg
+    );
+    if( rc==SQLITE_OK ){
+      if( pCsr->ePlan==FTS5_PLAN_ROWID ){
+        sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]);
+      }else{
+        sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iFirstRowid);
+        sqlite3_bind_int64(pCsr->pStmt, 2, pCsr->iLastRowid);
+      }
+      rc = fts5NextMethod(pCursor);
+    }
+  }
+
+  pConfig->pzErrmsg = pzErrmsg;
+  return rc;
+}
+
+/* 
+** This is the xEof method of the virtual table. SQLite calls this 
+** routine to find out if it has reached the end of a result set.
+*/
+static int fts5EofMethod(sqlite3_vtab_cursor *pCursor){
+  Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
+  return (CsrFlagTest(pCsr, FTS5CSR_EOF) ? 1 : 0);
+}
+
+/*
+** Return the rowid that the cursor currently points to.
+*/
+static i64 fts5CursorRowid(Fts5Cursor *pCsr){
+  assert( pCsr->ePlan==FTS5_PLAN_MATCH 
+       || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH 
+       || pCsr->ePlan==FTS5_PLAN_SOURCE 
+  );
+  if( pCsr->pSorter ){
+    return pCsr->pSorter->iRowid;
+  }else{
+    return sqlite3Fts5ExprRowid(pCsr->pExpr);
+  }
+}
+
+/* 
+** This is the xRowid method. The SQLite core calls this routine to
+** retrieve the rowid for the current row of the result set. fts5
+** exposes %_content.rowid as the rowid for the virtual table. The
+** rowid should be written to *pRowid.
+*/
+static int fts5RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
+  Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
+  int ePlan = pCsr->ePlan;
+  
+  assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 );
+  switch( ePlan ){
+    case FTS5_PLAN_SPECIAL:
+      *pRowid = 0;
+      break;
+
+    case FTS5_PLAN_SOURCE:
+    case FTS5_PLAN_MATCH:
+    case FTS5_PLAN_SORTED_MATCH:
+      *pRowid = fts5CursorRowid(pCsr);
+      break;
+
+    default:
+      *pRowid = sqlite3_column_int64(pCsr->pStmt, 0);
+      break;
+  }
+
+  return SQLITE_OK;
+}
+
+/*
+** If the cursor requires seeking (bSeekRequired flag is set), seek it.
+** Return SQLITE_OK if no error occurs, or an SQLite error code otherwise.
+**
+** If argument bErrormsg is true and an error occurs, an error message may
+** be left in sqlite3_vtab.zErrMsg.
+*/
+static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
+  int rc = SQLITE_OK;
+
+  /* If the cursor does not yet have a statement handle, obtain one now. */ 
+  if( pCsr->pStmt==0 ){
+    Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
+    int eStmt = fts5StmtType(pCsr);
+    rc = sqlite3Fts5StorageStmt(
+        pTab->pStorage, eStmt, &pCsr->pStmt, (bErrormsg?&pTab->base.zErrMsg:0)
+    );
+    assert( rc!=SQLITE_OK || pTab->base.zErrMsg==0 );
+    assert( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) );
+  }
+
+  if( rc==SQLITE_OK && CsrFlagTest(pCsr, FTS5CSR_REQUIRE_CONTENT) ){
+    assert( pCsr->pExpr );
+    sqlite3_reset(pCsr->pStmt);
+    sqlite3_bind_int64(pCsr->pStmt, 1, fts5CursorRowid(pCsr));
+    rc = sqlite3_step(pCsr->pStmt);
+    if( rc==SQLITE_ROW ){
+      rc = SQLITE_OK;
+      CsrFlagClear(pCsr, FTS5CSR_REQUIRE_CONTENT);
+    }else{
+      rc = sqlite3_reset(pCsr->pStmt);
+      if( rc==SQLITE_OK ){
+        rc = FTS5_CORRUPT;
+      }
+    }
+  }
+  return rc;
+}
+
+static void fts5SetVtabError(Fts5Table *p, const char *zFormat, ...){
+  va_list ap;                     /* ... printf arguments */
+  va_start(ap, zFormat);
+  assert( p->base.zErrMsg==0 );
+  p->base.zErrMsg = sqlite3_vmprintf(zFormat, ap);
+  va_end(ap);
+}
+
+/*
+** This function is called to handle an FTS INSERT command. In other words,
+** an INSERT statement of the form:
+**
+**     INSERT INTO fts(fts) VALUES($pCmd)
+**     INSERT INTO fts(fts, rank) VALUES($pCmd, $pVal)
+**
+** Argument pVal is the value assigned to column "fts" by the INSERT 
+** statement. This function returns SQLITE_OK if successful, or an SQLite
+** error code if an error occurs.
+**
+** The commands implemented by this function are documented in the "Special
+** INSERT Directives" section of the documentation. It should be updated if
+** more commands are added to this function.
+*/
+static int fts5SpecialInsert(
+  Fts5Table *pTab,                /* Fts5 table object */
+  const char *zCmd,               /* Text inserted into table-name column */
+  sqlite3_value *pVal             /* Value inserted into rank column */
+){
+  Fts5Config *pConfig = pTab->pConfig;
+  int rc = SQLITE_OK;
+  int bError = 0;
+
+  if( 0==sqlite3_stricmp("delete-all", zCmd) ){
+    if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
+      fts5SetVtabError(pTab, 
+          "'delete-all' may only be used with a "
+          "contentless or external content fts5 table"
+      );
+      rc = SQLITE_ERROR;
+    }else{
+      rc = sqlite3Fts5StorageDeleteAll(pTab->pStorage);
+    }
+  }else if( 0==sqlite3_stricmp("rebuild", zCmd) ){
+    if( pConfig->eContent==FTS5_CONTENT_NONE ){
+      fts5SetVtabError(pTab, 
+          "'rebuild' may not be used with a contentless fts5 table"
+      );
+      rc = SQLITE_ERROR;
+    }else{
+      rc = sqlite3Fts5StorageRebuild(pTab->pStorage);
+    }
+  }else if( 0==sqlite3_stricmp("optimize", zCmd) ){
+    rc = sqlite3Fts5StorageOptimize(pTab->pStorage);
+  }else if( 0==sqlite3_stricmp("merge", zCmd) ){
+    int nMerge = sqlite3_value_int(pVal);
+    rc = sqlite3Fts5StorageMerge(pTab->pStorage, nMerge);
+  }else if( 0==sqlite3_stricmp("integrity-check", zCmd) ){
+    rc = sqlite3Fts5StorageIntegrity(pTab->pStorage);
+#ifdef SQLITE_DEBUG
+  }else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){
+    pConfig->bPrefixIndex = sqlite3_value_int(pVal);
+#endif
+  }else{
+    rc = sqlite3Fts5IndexLoadConfig(pTab->pIndex);
+    if( rc==SQLITE_OK ){
+      rc = sqlite3Fts5ConfigSetValue(pTab->pConfig, zCmd, pVal, &bError);
+    }
+    if( rc==SQLITE_OK ){
+      if( bError ){
+        rc = SQLITE_ERROR;
+      }else{
+        rc = sqlite3Fts5StorageConfigValue(pTab->pStorage, zCmd, pVal, 0);
+      }
+    }
+  }
+  return rc;
+}
+
+static int fts5SpecialDelete(
+  Fts5Table *pTab, 
+  sqlite3_value **apVal, 
+  sqlite3_int64 *piRowid
+){
+  int rc = SQLITE_OK;
+  int eType1 = sqlite3_value_type(apVal[1]);
+  if( eType1==SQLITE_INTEGER ){
+    sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]);
+    rc = sqlite3Fts5StorageSpecialDelete(pTab->pStorage, iDel, &apVal[2]);
+  }
+  return rc;
+}
+
+static void fts5StorageInsert(
+  int *pRc, 
+  Fts5Table *pTab, 
+  sqlite3_value **apVal, 
+  i64 *piRowid
+){
+  int rc = *pRc;
+  if( rc==SQLITE_OK ){
+    rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, piRowid);
+  }
+  if( rc==SQLITE_OK ){
+    rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *piRowid);
+  }
+  *pRc = rc;
+}
+
+/* 
+** This function is the implementation of the xUpdate callback used by 
+** FTS3 virtual tables. It is invoked by SQLite each time a row is to be
+** inserted, updated or deleted.
+**
+** A delete specifies a single argument - the rowid of the row to remove.
+** 
+** Update and insert operations pass:
+**
+**   1. The "old" rowid, or NULL.
+**   2. The "new" rowid.
+**   3. Values for each of the nCol matchable columns.
+**   4. Values for the two hidden columns (<tablename> and "rank").
+*/
+static int fts5UpdateMethod(
+  sqlite3_vtab *pVtab,            /* Virtual table handle */
+  int nArg,                       /* Size of argument array */
+  sqlite3_value **apVal,          /* Array of arguments */
+  sqlite_int64 *pRowid            /* OUT: The affected (or effected) rowid */
+){
+  Fts5Table *pTab = (Fts5Table*)pVtab;
+  Fts5Config *pConfig = pTab->pConfig;
+  int eType0;                     /* value_type() of apVal[0] */
+  int rc = SQLITE_OK;             /* Return code */
+
+  /* A transaction must be open when this is called. */
+  assert( pTab->ts.eState==1 );
+
+  assert( pVtab->zErrMsg==0 );
+  assert( nArg==1 || nArg==(2+pConfig->nCol+2) );
+  assert( nArg==1 
+      || sqlite3_value_type(apVal[1])==SQLITE_INTEGER 
+      || sqlite3_value_type(apVal[1])==SQLITE_NULL 
+  );
+  assert( pTab->pConfig->pzErrmsg==0 );
+  pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg;
+
+  /* Put any active cursors into REQUIRE_SEEK state. */
+  fts5TripCursors(pTab);
+
+  eType0 = sqlite3_value_type(apVal[0]);
+  if( eType0==SQLITE_NULL 
+   && sqlite3_value_type(apVal[2+pConfig->nCol])!=SQLITE_NULL 
+  ){
+    /* A "special" INSERT op. These are handled separately. */
+    const char *z = (const char*)sqlite3_value_text(apVal[2+pConfig->nCol]);
+    if( pConfig->eContent!=FTS5_CONTENT_NORMAL 
+      && 0==sqlite3_stricmp("delete", z) 
+    ){
+      rc = fts5SpecialDelete(pTab, apVal, pRowid);
+    }else{
+      rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]);
+    }
+  }else{
+    /* A regular INSERT, UPDATE or DELETE statement. The trick here is that
+    ** any conflict on the rowid value must be detected before any 
+    ** modifications are made to the database file. There are 4 cases:
+    **
+    **   1) DELETE
+    **   2) UPDATE (rowid not modified)
+    **   3) UPDATE (rowid modified)
+    **   4) INSERT
+    **
+    ** Cases 3 and 4 may violate the rowid constraint.
+    */
+    int eConflict = sqlite3_vtab_on_conflict(pConfig->db);
+
+    assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL );
+    assert( nArg!=1 || eType0==SQLITE_INTEGER );
+
+    /* Filter out attempts to run UPDATE or DELETE on contentless tables.
+    ** This is not suported.  */
+    if( eType0==SQLITE_INTEGER && fts5IsContentless(pTab) ){
+      pTab->base.zErrMsg = sqlite3_mprintf(
+          "cannot %s contentless fts5 table: %s", 
+          (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName
+      );
+      rc = SQLITE_ERROR;
+    }
+
+    /* Case 1: DELETE */
+    else if( nArg==1 ){
+      i64 iDel = sqlite3_value_int64(apVal[0]);  /* Rowid to delete */
+      rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel);
+    }
+
+    /* Case 2: INSERT */
+    else if( eType0!=SQLITE_INTEGER ){     
+      /* If this is a REPLACE, first remove the current entry (if any) */
+      if( eConflict==SQLITE_REPLACE 
+       && sqlite3_value_type(apVal[1])==SQLITE_INTEGER 
+      ){
+        i64 iNew = sqlite3_value_int64(apVal[1]);  /* Rowid to delete */
+        rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew);
+      }
+      fts5StorageInsert(&rc, pTab, apVal, pRowid);
+    }
+
+    /* Case 2: UPDATE */
+    else{
+      i64 iOld = sqlite3_value_int64(apVal[0]);  /* Old rowid */
+      i64 iNew = sqlite3_value_int64(apVal[1]);  /* New rowid */
+      if( iOld!=iNew ){
+        if( eConflict==SQLITE_REPLACE ){
+          rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld);
+          if( rc==SQLITE_OK ){
+            rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew);
+          }
+          fts5StorageInsert(&rc, pTab, apVal, pRowid);
+        }else{
+          rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
+          if( rc==SQLITE_OK ){
+            rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld);
+          }
+          if( rc==SQLITE_OK ){
+            rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *pRowid);
+          }
+        }
+      }else{
+        rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld);
+        fts5StorageInsert(&rc, pTab, apVal, pRowid);
+      }
+    }
+  }
+
+  pTab->pConfig->pzErrmsg = 0;
+  return rc;
+}
+
+/*
+** Implementation of xSync() method. 
+*/
+static int fts5SyncMethod(sqlite3_vtab *pVtab){
+  int rc;
+  Fts5Table *pTab = (Fts5Table*)pVtab;
+  fts5CheckTransactionState(pTab, FTS5_SYNC, 0);
+  pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg;
+  fts5TripCursors(pTab);
+  rc = sqlite3Fts5StorageSync(pTab->pStorage, 1);
+  pTab->pConfig->pzErrmsg = 0;
+  return rc;
+}
+
+/*
+** Implementation of xBegin() method. 
+*/
+static int fts5BeginMethod(sqlite3_vtab *pVtab){
+  fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_BEGIN, 0);
+  return SQLITE_OK;
+}
+
+/*
+** Implementation of xCommit() method. This is a no-op. The contents of
+** the pending-terms hash-table have already been flushed into the database
+** by fts5SyncMethod().
+*/
+static int fts5CommitMethod(sqlite3_vtab *pVtab){
+  fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_COMMIT, 0);
+  return SQLITE_OK;
+}
+
+/*
+** Implementation of xRollback(). Discard the contents of the pending-terms
+** hash-table. Any changes made to the database are reverted by SQLite.
+*/
+static int fts5RollbackMethod(sqlite3_vtab *pVtab){
+  int rc;
+  Fts5Table *pTab = (Fts5Table*)pVtab;
+  fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0);
+  rc = sqlite3Fts5StorageRollback(pTab->pStorage);
+  return rc;
+}
+
+static void *fts5ApiUserData(Fts5Context *pCtx){
+  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+  return pCsr->pAux->pUserData;
+}
+
+static int fts5ApiColumnCount(Fts5Context *pCtx){
+  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+  return ((Fts5Table*)(pCsr->base.pVtab))->pConfig->nCol;
+}
+
+static int fts5ApiColumnTotalSize(
+  Fts5Context *pCtx, 
+  int iCol, 
+  sqlite3_int64 *pnToken
+){
+  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+  Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
+  return sqlite3Fts5StorageSize(pTab->pStorage, iCol, pnToken);
+}
+
+static int fts5ApiRowCount(Fts5Context *pCtx, i64 *pnRow){
+  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+  Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
+  return sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow);
+}
+
+static int fts5ApiTokenize(
+  Fts5Context *pCtx, 
+  const char *pText, int nText, 
+  void *pUserData,
+  int (*xToken)(void*, int, const char*, int, int, int)
+){
+  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+  Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
+  return sqlite3Fts5Tokenize(
+      pTab->pConfig, FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken
+  );
+}
+
+static int fts5ApiPhraseCount(Fts5Context *pCtx){
+  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+  return sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
+}
+
+static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){
+  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+  return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase);
+}
+
+static int fts5CsrPoslist(Fts5Cursor *pCsr, int iPhrase, const u8 **pa){
+  int n;
+  if( pCsr->pSorter ){
+    Fts5Sorter *pSorter = pCsr->pSorter;
+    int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
+    n = pSorter->aIdx[iPhrase] - i1;
+    *pa = &pSorter->aPoslist[i1];
+  }else{
+    n = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
+  }
+  return n;
+}
+
+/*
+** Ensure that the Fts5Cursor.nInstCount and aInst[] variables are populated
+** correctly for the current view. Return SQLITE_OK if successful, or an
+** SQLite error code otherwise.
+*/
+static int fts5CacheInstArray(Fts5Cursor *pCsr){
+  int rc = SQLITE_OK;
+  Fts5PoslistReader *aIter;       /* One iterator for each phrase */
+  int nIter;                      /* Number of iterators/phrases */
+  
+  nIter = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
+  if( pCsr->aInstIter==0 ){
+    int nByte = sizeof(Fts5PoslistReader) * nIter;
+    pCsr->aInstIter = (Fts5PoslistReader*)sqlite3Fts5MallocZero(&rc, nByte);
+  }
+  aIter = pCsr->aInstIter;
+
+  if( aIter ){
+    int nInst = 0;                /* Number instances seen so far */
+    int i;
+
+    /* Initialize all iterators */
+    for(i=0; i<nIter; i++){
+      const u8 *a;
+      int n = fts5CsrPoslist(pCsr, i, &a);
+      sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
+    }
+
+    while( 1 ){
+      int *aInst;
+      int iBest = -1;
+      for(i=0; i<nIter; i++){
+        if( (aIter[i].bEof==0) 
+         && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos) 
+        ){
+          iBest = i;
+        }
+      }
+      if( iBest<0 ) break;
+
+      nInst++;
+      if( nInst>=pCsr->nInstAlloc ){
+        pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32;
+        aInst = (int*)sqlite3_realloc(
+            pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3
+        );
+        if( aInst ){
+          pCsr->aInst = aInst;
+        }else{
+          rc = SQLITE_NOMEM;
+          break;
+        }
+      }
+
+      aInst = &pCsr->aInst[3 * (nInst-1)];
+      aInst[0] = iBest;
+      aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
+      aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
+      sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
+    }
+
+    pCsr->nInstCount = nInst;
+    CsrFlagClear(pCsr, FTS5CSR_REQUIRE_INST);
+  }
+  return rc;
+}
+
+static int fts5ApiInstCount(Fts5Context *pCtx, int *pnInst){
+  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+  int rc = SQLITE_OK;
+  if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0 
+   || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) ){
+    *pnInst = pCsr->nInstCount;
+  }
+  return rc;
+}
+
+static int fts5ApiInst(
+  Fts5Context *pCtx, 
+  int iIdx, 
+  int *piPhrase, 
+  int *piCol, 
+  int *piOff
+){
+  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+  int rc = SQLITE_OK;
+  if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0 
+   || SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) 
+  ){
+    if( iIdx<0 || iIdx>=pCsr->nInstCount ){
+      rc = SQLITE_RANGE;
+    }else{
+      *piPhrase = pCsr->aInst[iIdx*3];
+      *piCol = pCsr->aInst[iIdx*3 + 1];
+      *piOff = pCsr->aInst[iIdx*3 + 2];
+    }
+  }
+  return rc;
+}
+
+static sqlite3_int64 fts5ApiRowid(Fts5Context *pCtx){
+  return fts5CursorRowid((Fts5Cursor*)pCtx);
+}
+
+static int fts5ApiColumnText(
+  Fts5Context *pCtx, 
+  int iCol, 
+  const char **pz, 
+  int *pn
+){
+  int rc = SQLITE_OK;
+  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+  if( fts5IsContentless((Fts5Table*)(pCsr->base.pVtab)) ){
+    *pz = 0;
+    *pn = 0;
+  }else{
+    rc = fts5SeekCursor(pCsr, 0);
+    if( rc==SQLITE_OK ){
+      *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1);
+      *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
+    }
+  }
+  return rc;
+}
+
+static int fts5ColumnSizeCb(
+  void *pContext,                 /* Pointer to int */
+  int tflags,
+  const char *pToken,             /* Buffer containing token */
+  int nToken,                     /* Size of token in bytes */
+  int iStart,                     /* Start offset of token */
+  int iEnd                        /* End offset of token */
+){
+  int *pCnt = (int*)pContext;
+  if( (tflags & FTS5_TOKEN_COLOCATED)==0 ){
+    (*pCnt)++;
+  }
+  return SQLITE_OK;
+}
+
+static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){
+  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+  Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
+  Fts5Config *pConfig = pTab->pConfig;
+  int rc = SQLITE_OK;
+
+  if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_DOCSIZE) ){
+    if( pConfig->bColumnsize ){
+      i64 iRowid = fts5CursorRowid(pCsr);
+      rc = sqlite3Fts5StorageDocsize(pTab->pStorage, iRowid, pCsr->aColumnSize);
+    }else if( pConfig->zContent==0 ){
+      int i;
+      for(i=0; i<pConfig->nCol; i++){
+        if( pConfig->abUnindexed[i]==0 ){
+          pCsr->aColumnSize[i] = -1;
+        }
+      }
+    }else{
+      int i;
+      for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
+        if( pConfig->abUnindexed[i]==0 ){
+          const char *z; int n;
+          void *p = (void*)(&pCsr->aColumnSize[i]);
+          pCsr->aColumnSize[i] = 0;
+          rc = fts5ApiColumnText(pCtx, i, &z, &n);
+          if( rc==SQLITE_OK ){
+            rc = sqlite3Fts5Tokenize(
+                pConfig, FTS5_TOKENIZE_AUX, z, n, p, fts5ColumnSizeCb
+            );
+          }
+        }
+      }
+    }
+    CsrFlagClear(pCsr, FTS5CSR_REQUIRE_DOCSIZE);
+  }
+  if( iCol<0 ){
+    int i;
+    *pnToken = 0;
+    for(i=0; i<pConfig->nCol; i++){
+      *pnToken += pCsr->aColumnSize[i];
+    }
+  }else if( iCol<pConfig->nCol ){
+    *pnToken = pCsr->aColumnSize[iCol];
+  }else{
+    *pnToken = 0;
+    rc = SQLITE_RANGE;
+  }
+  return rc;
+}
+
+/*
+** Implementation of the xSetAuxdata() method.
+*/
+static int fts5ApiSetAuxdata(
+  Fts5Context *pCtx,              /* Fts5 context */
+  void *pPtr,                     /* Pointer to save as auxdata */
+  void(*xDelete)(void*)           /* Destructor for pPtr (or NULL) */
+){
+  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+  Fts5Auxdata *pData;
+
+  /* Search through the cursors list of Fts5Auxdata objects for one that
+  ** corresponds to the currently executing auxiliary function.  */
+  for(pData=pCsr->pAuxdata; pData; pData=pData->pNext){
+    if( pData->pAux==pCsr->pAux ) break;
+  }
+
+  if( pData ){
+    if( pData->xDelete ){
+      pData->xDelete(pData->pPtr);
+    }
+  }else{
+    int rc = SQLITE_OK;
+    pData = (Fts5Auxdata*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Auxdata));
+    if( pData==0 ){
+      if( xDelete ) xDelete(pPtr);
+      return rc;
+    }
+    pData->pAux = pCsr->pAux;
+    pData->pNext = pCsr->pAuxdata;
+    pCsr->pAuxdata = pData;
+  }
+
+  pData->xDelete = xDelete;
+  pData->pPtr = pPtr;
+  return SQLITE_OK;
+}
+
+static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){
+  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+  Fts5Auxdata *pData;
+  void *pRet = 0;
+
+  for(pData=pCsr->pAuxdata; pData; pData=pData->pNext){
+    if( pData->pAux==pCsr->pAux ) break;
+  }
+
+  if( pData ){
+    pRet = pData->pPtr;
+    if( bClear ){
+      pData->pPtr = 0;
+      pData->xDelete = 0;
+    }
+  }
+
+  return pRet;
+}
+
+static void fts5ApiPhraseNext(
+  Fts5Context *pCtx, 
+  Fts5PhraseIter *pIter, 
+  int *piCol, int *piOff
+){
+  if( pIter->a>=pIter->b ){
+    *piCol = -1;
+    *piOff = -1;
+  }else{
+    int iVal;
+    pIter->a += fts5GetVarint32(pIter->a, iVal);
+    if( iVal==1 ){
+      pIter->a += fts5GetVarint32(pIter->a, iVal);
+      *piCol = iVal;
+      *piOff = 0;
+      pIter->a += fts5GetVarint32(pIter->a, iVal);
+    }
+    *piOff += (iVal-2);
+  }
+}
+
+static void fts5ApiPhraseFirst(
+  Fts5Context *pCtx, 
+  int iPhrase, 
+  Fts5PhraseIter *pIter, 
+  int *piCol, int *piOff
+){
+  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+  int n = fts5CsrPoslist(pCsr, iPhrase, &pIter->a);
+  pIter->b = &pIter->a[n];
+  *piCol = 0;
+  *piOff = 0;
+  fts5ApiPhraseNext(pCtx, pIter, piCol, piOff);
+}
+
+static int fts5ApiQueryPhrase(Fts5Context*, int, void*, 
+    int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
+);
+
+static const Fts5ExtensionApi sFts5Api = {
+  2,                            /* iVersion */
+  fts5ApiUserData,
+  fts5ApiColumnCount,
+  fts5ApiRowCount,
+  fts5ApiColumnTotalSize,
+  fts5ApiTokenize,
+  fts5ApiPhraseCount,
+  fts5ApiPhraseSize,
+  fts5ApiInstCount,
+  fts5ApiInst,
+  fts5ApiRowid,
+  fts5ApiColumnText,
+  fts5ApiColumnSize,
+  fts5ApiQueryPhrase,
+  fts5ApiSetAuxdata,
+  fts5ApiGetAuxdata,
+  fts5ApiPhraseFirst,
+  fts5ApiPhraseNext,
+};
+
+
+/*
+** Implementation of API function xQueryPhrase().
+*/
+static int fts5ApiQueryPhrase(
+  Fts5Context *pCtx, 
+  int iPhrase, 
+  void *pUserData,
+  int(*xCallback)(const Fts5ExtensionApi*, Fts5Context*, void*)
+){
+  Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+  Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
+  int rc;
+  Fts5Cursor *pNew = 0;
+
+  rc = fts5OpenMethod(pCsr->base.pVtab, (sqlite3_vtab_cursor**)&pNew);
+  if( rc==SQLITE_OK ){
+    Fts5Config *pConf = pTab->pConfig;
+    pNew->ePlan = FTS5_PLAN_MATCH;
+    pNew->iFirstRowid = SMALLEST_INT64;
+    pNew->iLastRowid = LARGEST_INT64;
+    pNew->base.pVtab = (sqlite3_vtab*)pTab;
+    rc = sqlite3Fts5ExprClonePhrase(pConf, pCsr->pExpr, iPhrase, &pNew->pExpr);
+  }
+
+  if( rc==SQLITE_OK ){
+    for(rc = fts5CursorFirst(pTab, pNew, 0);
+        rc==SQLITE_OK && CsrFlagTest(pNew, FTS5CSR_EOF)==0;
+        rc = fts5NextMethod((sqlite3_vtab_cursor*)pNew)
+    ){
+      rc = xCallback(&sFts5Api, (Fts5Context*)pNew, pUserData);
+      if( rc!=SQLITE_OK ){
+        if( rc==SQLITE_DONE ) rc = SQLITE_OK;
+        break;
+      }
+    }
+  }
+
+  fts5CloseMethod((sqlite3_vtab_cursor*)pNew);
+  return rc;
+}
+
+static void fts5ApiInvoke(
+  Fts5Auxiliary *pAux,
+  Fts5Cursor *pCsr,
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  assert( pCsr->pAux==0 );
+  pCsr->pAux = pAux;
+  pAux->xFunc(&sFts5Api, (Fts5Context*)pCsr, context, argc, argv);
+  pCsr->pAux = 0;
+}
+
+static Fts5Cursor *fts5CursorFromCsrid(Fts5Global *pGlobal, i64 iCsrId){
+  Fts5Cursor *pCsr;
+  for(pCsr=pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
+    if( pCsr->iCsrId==iCsrId ) break;
+  }
+  return pCsr;
+}
+
+static void fts5ApiCallback(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+
+  Fts5Auxiliary *pAux;
+  Fts5Cursor *pCsr;
+  i64 iCsrId;
+
+  assert( argc>=1 );
+  pAux = (Fts5Auxiliary*)sqlite3_user_data(context);
+  iCsrId = sqlite3_value_int64(argv[0]);
+
+  pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId);
+  if( pCsr==0 ){
+    char *zErr = sqlite3_mprintf("no such cursor: %lld", iCsrId);
+    sqlite3_result_error(context, zErr, -1);
+    sqlite3_free(zErr);
+  }else{
+    fts5ApiInvoke(pAux, pCsr, context, argc-1, &argv[1]);
+  }
+}
+
+
+/*
+** Given cursor id iId, return a pointer to the corresponding Fts5Index 
+** object. Or NULL If the cursor id does not exist.
+**
+** If successful, set *pnCol to the number of indexed columns in the
+** table before returning.
+*/
+static Fts5Index *sqlite3Fts5IndexFromCsrid(
+  Fts5Global *pGlobal, 
+  i64 iCsrId, 
+  int *pnCol
+){
+  Fts5Cursor *pCsr;
+  Fts5Table *pTab;
+
+  pCsr = fts5CursorFromCsrid(pGlobal, iCsrId);
+  pTab = (Fts5Table*)pCsr->base.pVtab;
+  *pnCol = pTab->pConfig->nCol;
+
+  return pTab->pIndex;
+}
+
+/*
+** Return a "position-list blob" corresponding to the current position of
+** cursor pCsr via sqlite3_result_blob(). A position-list blob contains
+** the current position-list for each phrase in the query associated with
+** cursor pCsr.
+**
+** A position-list blob begins with (nPhrase-1) varints, where nPhrase is
+** the number of phrases in the query. Following the varints are the
+** concatenated position lists for each phrase, in order.
+**
+** The first varint (if it exists) contains the size of the position list
+** for phrase 0. The second (same disclaimer) contains the size of position
+** list 1. And so on. There is no size field for the final position list,
+** as it can be derived from the total size of the blob.
+*/
+static int fts5PoslistBlob(sqlite3_context *pCtx, Fts5Cursor *pCsr){
+  int i;
+  int rc = SQLITE_OK;
+  int nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
+  Fts5Buffer val;
+
+  memset(&val, 0, sizeof(Fts5Buffer));
+
+  /* Append the varints */
+  for(i=0; i<(nPhrase-1); i++){
+    const u8 *dummy;
+    int nByte = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &dummy);
+    sqlite3Fts5BufferAppendVarint(&rc, &val, nByte);
+  }
+
+  /* Append the position lists */
+  for(i=0; i<nPhrase; i++){
+    const u8 *pPoslist;
+    int nPoslist;
+    nPoslist = sqlite3Fts5ExprPoslist(pCsr->pExpr, i, &pPoslist);
+    sqlite3Fts5BufferAppendBlob(&rc, &val, nPoslist, pPoslist);
+  }
+
+  sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free);
+  return rc;
+}
+
+/* 
+** This is the xColumn method, called by SQLite to request a value from
+** the row that the supplied cursor currently points to.
+*/
+static int fts5ColumnMethod(
+  sqlite3_vtab_cursor *pCursor,   /* Cursor to retrieve value from */
+  sqlite3_context *pCtx,          /* Context for sqlite3_result_xxx() calls */
+  int iCol                        /* Index of column to read value from */
+){
+  Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab);
+  Fts5Config *pConfig = pTab->pConfig;
+  Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
+  int rc = SQLITE_OK;
+  
+  assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 );
+
+  if( pCsr->ePlan==FTS5_PLAN_SPECIAL ){
+    if( iCol==pConfig->nCol ){
+      sqlite3_result_int64(pCtx, pCsr->iSpecial);
+    }
+  }else
+
+  if( iCol==pConfig->nCol ){
+    /* User is requesting the value of the special column with the same name
+    ** as the table. Return the cursor integer id number. This value is only
+    ** useful in that it may be passed as the first argument to an FTS5
+    ** auxiliary function.  */
+    sqlite3_result_int64(pCtx, pCsr->iCsrId);
+  }else if( iCol==pConfig->nCol+1 ){
+
+    /* The value of the "rank" column. */
+    if( pCsr->ePlan==FTS5_PLAN_SOURCE ){
+      fts5PoslistBlob(pCtx, pCsr);
+    }else if( 
+        pCsr->ePlan==FTS5_PLAN_MATCH
+     || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
+    ){
+      if( pCsr->pRank || SQLITE_OK==(rc = fts5FindRankFunction(pCsr)) ){
+        fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg);
+      }
+    }
+  }else if( !fts5IsContentless(pTab) ){
+    rc = fts5SeekCursor(pCsr, 1);
+    if( rc==SQLITE_OK ){
+      sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
+    }
+  }
+  return rc;
+}
+
+
+/*
+** This routine implements the xFindFunction method for the FTS3
+** virtual table.
+*/
+static int fts5FindFunctionMethod(
+  sqlite3_vtab *pVtab,            /* Virtual table handle */
+  int nArg,                       /* Number of SQL function arguments */
+  const char *zName,              /* Name of SQL function */
+  void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */
+  void **ppArg                    /* OUT: User data for *pxFunc */
+){
+  Fts5Table *pTab = (Fts5Table*)pVtab;
+  Fts5Auxiliary *pAux;
+
+  pAux = fts5FindAuxiliary(pTab, zName);
+  if( pAux ){
+    *pxFunc = fts5ApiCallback;
+    *ppArg = (void*)pAux;
+    return 1;
+  }
+
+  /* No function of the specified name was found. Return 0. */
+  return 0;
+}
+
+/*
+** Implementation of FTS5 xRename method. Rename an fts5 table.
+*/
+static int fts5RenameMethod(
+  sqlite3_vtab *pVtab,            /* Virtual table handle */
+  const char *zName               /* New name of table */
+){
+  Fts5Table *pTab = (Fts5Table*)pVtab;
+  return sqlite3Fts5StorageRename(pTab->pStorage, zName);
+}
+
+/*
+** The xSavepoint() method.
+**
+** Flush the contents of the pending-terms table to disk.
+*/
+static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
+  Fts5Table *pTab = (Fts5Table*)pVtab;
+  fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
+  fts5TripCursors(pTab);
+  return sqlite3Fts5StorageSync(pTab->pStorage, 0);
+}
+
+/*
+** The xRelease() method.
+**
+** This is a no-op.
+*/
+static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
+  Fts5Table *pTab = (Fts5Table*)pVtab;
+  fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint);
+  fts5TripCursors(pTab);
+  return sqlite3Fts5StorageSync(pTab->pStorage, 0);
+}
+
+/*
+** The xRollbackTo() method.
+**
+** Discard the contents of the pending terms table.
+*/
+static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
+  Fts5Table *pTab = (Fts5Table*)pVtab;
+  fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
+  fts5TripCursors(pTab);
+  return sqlite3Fts5StorageRollback(pTab->pStorage);
+}
+
+/*
+** Register a new auxiliary function with global context pGlobal.
+*/
+static int fts5CreateAux(
+  fts5_api *pApi,                 /* Global context (one per db handle) */
+  const char *zName,              /* Name of new function */
+  void *pUserData,                /* User data for aux. function */
+  fts5_extension_function xFunc,  /* Aux. function implementation */
+  void(*xDestroy)(void*)          /* Destructor for pUserData */
+){
+  Fts5Global *pGlobal = (Fts5Global*)pApi;
+  int rc = sqlite3_overload_function(pGlobal->db, zName, -1);
+  if( rc==SQLITE_OK ){
+    Fts5Auxiliary *pAux;
+    int nName;                      /* Size of zName in bytes, including \0 */
+    int nByte;                      /* Bytes of space to allocate */
+
+    nName = (int)strlen(zName) + 1;
+    nByte = sizeof(Fts5Auxiliary) + nName;
+    pAux = (Fts5Auxiliary*)sqlite3_malloc(nByte);
+    if( pAux ){
+      memset(pAux, 0, nByte);
+      pAux->zFunc = (char*)&pAux[1];
+      memcpy(pAux->zFunc, zName, nName);
+      pAux->pGlobal = pGlobal;
+      pAux->pUserData = pUserData;
+      pAux->xFunc = xFunc;
+      pAux->xDestroy = xDestroy;
+      pAux->pNext = pGlobal->pAux;
+      pGlobal->pAux = pAux;
+    }else{
+      rc = SQLITE_NOMEM;
+    }
+  }
+
+  return rc;
+}
+
+/*
+** Register a new tokenizer. This is the implementation of the 
+** fts5_api.xCreateTokenizer() method.
+*/
+static int fts5CreateTokenizer(
+  fts5_api *pApi,                 /* Global context (one per db handle) */
+  const char *zName,              /* Name of new function */
+  void *pUserData,                /* User data for aux. function */
+  fts5_tokenizer *pTokenizer,     /* Tokenizer implementation */
+  void(*xDestroy)(void*)          /* Destructor for pUserData */
+){
+  Fts5Global *pGlobal = (Fts5Global*)pApi;
+  Fts5TokenizerModule *pNew;
+  int nName;                      /* Size of zName and its \0 terminator */
+  int nByte;                      /* Bytes of space to allocate */
+  int rc = SQLITE_OK;
+
+  nName = (int)strlen(zName) + 1;
+  nByte = sizeof(Fts5TokenizerModule) + nName;
+  pNew = (Fts5TokenizerModule*)sqlite3_malloc(nByte);
+  if( pNew ){
+    memset(pNew, 0, nByte);
+    pNew->zName = (char*)&pNew[1];
+    memcpy(pNew->zName, zName, nName);
+    pNew->pUserData = pUserData;
+    pNew->x = *pTokenizer;
+    pNew->xDestroy = xDestroy;
+    pNew->pNext = pGlobal->pTok;
+    pGlobal->pTok = pNew;
+    if( pNew->pNext==0 ){
+      pGlobal->pDfltTok = pNew;
+    }
+  }else{
+    rc = SQLITE_NOMEM;
+  }
+
+  return rc;
+}
+
+static Fts5TokenizerModule *fts5LocateTokenizer(
+  Fts5Global *pGlobal, 
+  const char *zName
+){
+  Fts5TokenizerModule *pMod = 0;
+
+  if( zName==0 ){
+    pMod = pGlobal->pDfltTok;
+  }else{
+    for(pMod=pGlobal->pTok; pMod; pMod=pMod->pNext){
+      if( sqlite3_stricmp(zName, pMod->zName)==0 ) break;
+    }
+  }
+
+  return pMod;
+}
+
+/*
+** Find a tokenizer. This is the implementation of the 
+** fts5_api.xFindTokenizer() method.
+*/
+static int fts5FindTokenizer(
+  fts5_api *pApi,                 /* Global context (one per db handle) */
+  const char *zName,              /* Name of new function */
+  void **ppUserData,
+  fts5_tokenizer *pTokenizer      /* Populate this object */
+){
+  int rc = SQLITE_OK;
+  Fts5TokenizerModule *pMod;
+
+  pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName);
+  if( pMod ){
+    *pTokenizer = pMod->x;
+    *ppUserData = pMod->pUserData;
+  }else{
+    memset(pTokenizer, 0, sizeof(fts5_tokenizer));
+    rc = SQLITE_ERROR;
+  }
+
+  return rc;
+}
+
+static int sqlite3Fts5GetTokenizer(
+  Fts5Global *pGlobal, 
+  const char **azArg,
+  int nArg,
+  Fts5Tokenizer **ppTok,
+  fts5_tokenizer **ppTokApi,
+  char **pzErr
+){
+  Fts5TokenizerModule *pMod;
+  int rc = SQLITE_OK;
+
+  pMod = fts5LocateTokenizer(pGlobal, nArg==0 ? 0 : azArg[0]);
+  if( pMod==0 ){
+    assert( nArg>0 );
+    rc = SQLITE_ERROR;
+    *pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]);
+  }else{
+    rc = pMod->x.xCreate(pMod->pUserData, &azArg[1], (nArg?nArg-1:0), ppTok);
+    *ppTokApi = &pMod->x;
+    if( rc!=SQLITE_OK && pzErr ){
+      *pzErr = sqlite3_mprintf("error in tokenizer constructor");
+    }
+  }
+
+  if( rc!=SQLITE_OK ){
+    *ppTokApi = 0;
+    *ppTok = 0;
+  }
+
+  return rc;
+}
+
+static void fts5ModuleDestroy(void *pCtx){
+  Fts5TokenizerModule *pTok, *pNextTok;
+  Fts5Auxiliary *pAux, *pNextAux;
+  Fts5Global *pGlobal = (Fts5Global*)pCtx;
+
+  for(pAux=pGlobal->pAux; pAux; pAux=pNextAux){
+    pNextAux = pAux->pNext;
+    if( pAux->xDestroy ) pAux->xDestroy(pAux->pUserData);
+    sqlite3_free(pAux);
+  }
+
+  for(pTok=pGlobal->pTok; pTok; pTok=pNextTok){
+    pNextTok = pTok->pNext;
+    if( pTok->xDestroy ) pTok->xDestroy(pTok->pUserData);
+    sqlite3_free(pTok);
+  }
+
+  sqlite3_free(pGlobal);
+}
+
+static void fts5Fts5Func(
+  sqlite3_context *pCtx,          /* Function call context */
+  int nArg,                       /* Number of args */
+  sqlite3_value **apVal           /* Function arguments */
+){
+  Fts5Global *pGlobal = (Fts5Global*)sqlite3_user_data(pCtx);
+  char buf[8];
+  assert( nArg==0 );
+  assert( sizeof(buf)>=sizeof(pGlobal) );
+  memcpy(buf, (void*)&pGlobal, sizeof(pGlobal));
+  sqlite3_result_blob(pCtx, buf, sizeof(pGlobal), SQLITE_TRANSIENT);
+}
+
+/*
+** Implementation of fts5_source_id() function.
+*/
+static void fts5SourceIdFunc(
+  sqlite3_context *pCtx,          /* Function call context */
+  int nArg,                       /* Number of args */
+  sqlite3_value **apVal           /* Function arguments */
+){
+  assert( nArg==0 );
+  sqlite3_result_text(pCtx, "fts5: 2015-10-14 12:29:53 a721fc0d89495518fe5612e2e3bbc60befd2e90d", -1, SQLITE_TRANSIENT);
+}
+
+static int fts5Init(sqlite3 *db){
+  static const sqlite3_module fts5Mod = {
+    /* iVersion      */ 2,
+    /* xCreate       */ fts5CreateMethod,
+    /* xConnect      */ fts5ConnectMethod,
+    /* xBestIndex    */ fts5BestIndexMethod,
+    /* xDisconnect   */ fts5DisconnectMethod,
+    /* xDestroy      */ fts5DestroyMethod,
+    /* xOpen         */ fts5OpenMethod,
+    /* xClose        */ fts5CloseMethod,
+    /* xFilter       */ fts5FilterMethod,
+    /* xNext         */ fts5NextMethod,
+    /* xEof          */ fts5EofMethod,
+    /* xColumn       */ fts5ColumnMethod,
+    /* xRowid        */ fts5RowidMethod,
+    /* xUpdate       */ fts5UpdateMethod,
+    /* xBegin        */ fts5BeginMethod,
+    /* xSync         */ fts5SyncMethod,
+    /* xCommit       */ fts5CommitMethod,
+    /* xRollback     */ fts5RollbackMethod,
+    /* xFindFunction */ fts5FindFunctionMethod,
+    /* xRename       */ fts5RenameMethod,
+    /* xSavepoint    */ fts5SavepointMethod,
+    /* xRelease      */ fts5ReleaseMethod,
+    /* xRollbackTo   */ fts5RollbackToMethod,
+  };
+
+  int rc;
+  Fts5Global *pGlobal = 0;
+
+  pGlobal = (Fts5Global*)sqlite3_malloc(sizeof(Fts5Global));
+  if( pGlobal==0 ){
+    rc = SQLITE_NOMEM;
+  }else{
+    void *p = (void*)pGlobal;
+    memset(pGlobal, 0, sizeof(Fts5Global));
+    pGlobal->db = db;
+    pGlobal->api.iVersion = 2;
+    pGlobal->api.xCreateFunction = fts5CreateAux;
+    pGlobal->api.xCreateTokenizer = fts5CreateTokenizer;
+    pGlobal->api.xFindTokenizer = fts5FindTokenizer;
+    rc = sqlite3_create_module_v2(db, "fts5", &fts5Mod, p, fts5ModuleDestroy);
+    if( rc==SQLITE_OK ) rc = sqlite3Fts5IndexInit(db);
+    if( rc==SQLITE_OK ) rc = sqlite3Fts5ExprInit(pGlobal, db);
+    if( rc==SQLITE_OK ) rc = sqlite3Fts5AuxInit(&pGlobal->api);
+    if( rc==SQLITE_OK ) rc = sqlite3Fts5TokenizerInit(&pGlobal->api);
+    if( rc==SQLITE_OK ) rc = sqlite3Fts5VocabInit(pGlobal, db);
+    if( rc==SQLITE_OK ){
+      rc = sqlite3_create_function(
+          db, "fts5", 0, SQLITE_UTF8, p, fts5Fts5Func, 0, 0
+      );
+    }
+    if( rc==SQLITE_OK ){
+      rc = sqlite3_create_function(
+          db, "fts5_source_id", 0, SQLITE_UTF8, p, fts5SourceIdFunc, 0, 0
+      );
+    }
+  }
+  return rc;
+}
+
+/*
+** The following functions are used to register the module with SQLite. If
+** this module is being built as part of the SQLite core (SQLITE_CORE is
+** defined), then sqlite3_open() will call sqlite3Fts5Init() directly.
+**
+** Or, if this module is being built as a loadable extension, 
+** sqlite3Fts5Init() is omitted and the two standard entry points
+** sqlite3_fts_init() and sqlite3_fts5_init() defined instead.
+*/
+#ifndef SQLITE_CORE
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+SQLITE_API int SQLITE_STDCALL sqlite3_fts_init(
+  sqlite3 *db,
+  char **pzErrMsg,
+  const sqlite3_api_routines *pApi
+){
+  SQLITE_EXTENSION_INIT2(pApi);
+  (void)pzErrMsg;  /* Unused parameter */
+  return fts5Init(db);
+}
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+SQLITE_API int SQLITE_STDCALL sqlite3_fts5_init(
+  sqlite3 *db,
+  char **pzErrMsg,
+  const sqlite3_api_routines *pApi
+){
+  SQLITE_EXTENSION_INIT2(pApi);
+  (void)pzErrMsg;  /* Unused parameter */
+  return fts5Init(db);
+}
+#else
+SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3 *db){
+  return fts5Init(db);
+}
+#endif
+
+/*
+** 2014 May 31
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+*/
+
+
+
+
+struct Fts5Storage {
+  Fts5Config *pConfig;
+  Fts5Index *pIndex;
+  int bTotalsValid;               /* True if nTotalRow/aTotalSize[] are valid */
+  i64 nTotalRow;                  /* Total number of rows in FTS table */
+  i64 *aTotalSize;                /* Total sizes of each column */ 
+  sqlite3_stmt *aStmt[11];
+};
+
+
+#if FTS5_STMT_SCAN_ASC!=0 
+# error "FTS5_STMT_SCAN_ASC mismatch" 
+#endif
+#if FTS5_STMT_SCAN_DESC!=1 
+# error "FTS5_STMT_SCAN_DESC mismatch" 
+#endif
+#if FTS5_STMT_LOOKUP!=2
+# error "FTS5_STMT_LOOKUP mismatch" 
+#endif
+
+#define FTS5_STMT_INSERT_CONTENT  3
+#define FTS5_STMT_REPLACE_CONTENT 4
+#define FTS5_STMT_DELETE_CONTENT  5
+#define FTS5_STMT_REPLACE_DOCSIZE  6
+#define FTS5_STMT_DELETE_DOCSIZE  7
+#define FTS5_STMT_LOOKUP_DOCSIZE  8
+#define FTS5_STMT_REPLACE_CONFIG 9
+#define FTS5_STMT_SCAN 10
+
+/*
+** Prepare the two insert statements - Fts5Storage.pInsertContent and
+** Fts5Storage.pInsertDocsize - if they have not already been prepared.
+** Return SQLITE_OK if successful, or an SQLite error code if an error
+** occurs.
+*/
+static int fts5StorageGetStmt(
+  Fts5Storage *p,                 /* Storage handle */
+  int eStmt,                      /* FTS5_STMT_XXX constant */
+  sqlite3_stmt **ppStmt,          /* OUT: Prepared statement handle */
+  char **pzErrMsg                 /* OUT: Error message (if any) */
+){
+  int rc = SQLITE_OK;
+
+  /* If there is no %_docsize table, there should be no requests for 
+  ** statements to operate on it.  */
+  assert( p->pConfig->bColumnsize || (
+        eStmt!=FTS5_STMT_REPLACE_DOCSIZE 
+     && eStmt!=FTS5_STMT_DELETE_DOCSIZE 
+     && eStmt!=FTS5_STMT_LOOKUP_DOCSIZE 
+  ));
+
+  assert( eStmt>=0 && eStmt<ArraySize(p->aStmt) );
+  if( p->aStmt[eStmt]==0 ){
+    const char *azStmt[] = {
+      "SELECT %s FROM %s T WHERE T.%Q >= ? AND T.%Q <= ? ORDER BY T.%Q ASC",
+      "SELECT %s FROM %s T WHERE T.%Q <= ? AND T.%Q >= ? ORDER BY T.%Q DESC",
+      "SELECT %s FROM %s T WHERE T.%Q=?",               /* LOOKUP  */
+
+      "INSERT INTO %Q.'%q_content' VALUES(%s)",         /* INSERT_CONTENT  */
+      "REPLACE INTO %Q.'%q_content' VALUES(%s)",        /* REPLACE_CONTENT */
+      "DELETE FROM %Q.'%q_content' WHERE id=?",         /* DELETE_CONTENT  */
+      "REPLACE INTO %Q.'%q_docsize' VALUES(?,?)",       /* REPLACE_DOCSIZE  */
+      "DELETE FROM %Q.'%q_docsize' WHERE id=?",         /* DELETE_DOCSIZE  */
+
+      "SELECT sz FROM %Q.'%q_docsize' WHERE id=?",      /* LOOKUP_DOCSIZE  */
+
+      "REPLACE INTO %Q.'%q_config' VALUES(?,?)",        /* REPLACE_CONFIG */
+      "SELECT %s FROM %s AS T",                         /* SCAN */
+    };
+    Fts5Config *pC = p->pConfig;
+    char *zSql = 0;
+
+    switch( eStmt ){
+      case FTS5_STMT_SCAN:
+        zSql = sqlite3_mprintf(azStmt[eStmt], 
+            pC->zContentExprlist, pC->zContent
+        );
+        break;
+
+      case FTS5_STMT_SCAN_ASC:
+      case FTS5_STMT_SCAN_DESC:
+        zSql = sqlite3_mprintf(azStmt[eStmt], pC->zContentExprlist, 
+            pC->zContent, pC->zContentRowid, pC->zContentRowid,
+            pC->zContentRowid
+        );
+        break;
+
+      case FTS5_STMT_LOOKUP:
+        zSql = sqlite3_mprintf(azStmt[eStmt], 
+            pC->zContentExprlist, pC->zContent, pC->zContentRowid
+        );
+        break;
+
+      case FTS5_STMT_INSERT_CONTENT: 
+      case FTS5_STMT_REPLACE_CONTENT: {
+        int nCol = pC->nCol + 1;
+        char *zBind;
+        int i;
+
+        zBind = sqlite3_malloc(1 + nCol*2);
+        if( zBind ){
+          for(i=0; i<nCol; i++){
+            zBind[i*2] = '?';
+            zBind[i*2 + 1] = ',';
+          }
+          zBind[i*2-1] = '\0';
+          zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName, zBind);
+          sqlite3_free(zBind);
+        }
+        break;
+      }
+
+      default:
+        zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName);
+        break;
+    }
+
+    if( zSql==0 ){
+      rc = SQLITE_NOMEM;
+    }else{
+      rc = sqlite3_prepare_v2(pC->db, zSql, -1, &p->aStmt[eStmt], 0);
+      sqlite3_free(zSql);
+      if( rc!=SQLITE_OK && pzErrMsg ){
+        *pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db));
+      }
+    }
+  }
+
+  *ppStmt = p->aStmt[eStmt];
+  return rc;
+}
+
+
+static int fts5ExecPrintf(
+  sqlite3 *db,
+  char **pzErr,
+  const char *zFormat,
+  ...
+){
+  int rc;
+  va_list ap;                     /* ... printf arguments */
+  char *zSql;
+
+  va_start(ap, zFormat);
+  zSql = sqlite3_vmprintf(zFormat, ap);
+
+  if( zSql==0 ){
+    rc = SQLITE_NOMEM;
+  }else{
+    rc = sqlite3_exec(db, zSql, 0, 0, pzErr);
+    sqlite3_free(zSql);
+  }
+
+  va_end(ap);
+  return rc;
+}
+
+/*
+** Drop all shadow tables. Return SQLITE_OK if successful or an SQLite error
+** code otherwise.
+*/
+static int sqlite3Fts5DropAll(Fts5Config *pConfig){
+  int rc = fts5ExecPrintf(pConfig->db, 0, 
+      "DROP TABLE IF EXISTS %Q.'%q_data';"
+      "DROP TABLE IF EXISTS %Q.'%q_idx';"
+      "DROP TABLE IF EXISTS %Q.'%q_config';",
+      pConfig->zDb, pConfig->zName,
+      pConfig->zDb, pConfig->zName,
+      pConfig->zDb, pConfig->zName
+  );
+  if( rc==SQLITE_OK && pConfig->bColumnsize ){
+    rc = fts5ExecPrintf(pConfig->db, 0, 
+        "DROP TABLE IF EXISTS %Q.'%q_docsize';",
+        pConfig->zDb, pConfig->zName
+    );
+  }
+  if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
+    rc = fts5ExecPrintf(pConfig->db, 0, 
+        "DROP TABLE IF EXISTS %Q.'%q_content';",
+        pConfig->zDb, pConfig->zName
+    );
+  }
+  return rc;
+}
+
+static void fts5StorageRenameOne(
+  Fts5Config *pConfig,            /* Current FTS5 configuration */
+  int *pRc,                       /* IN/OUT: Error code */
+  const char *zTail,              /* Tail of table name e.g. "data", "config" */
+  const char *zName               /* New name of FTS5 table */
+){
+  if( *pRc==SQLITE_OK ){
+    *pRc = fts5ExecPrintf(pConfig->db, 0, 
+        "ALTER TABLE %Q.'%q_%s' RENAME TO '%q_%s';",
+        pConfig->zDb, pConfig->zName, zTail, zName, zTail
+    );
+  }
+}
+
+static int sqlite3Fts5StorageRename(Fts5Storage *pStorage, const char *zName){
+  Fts5Config *pConfig = pStorage->pConfig;
+  int rc = sqlite3Fts5StorageSync(pStorage, 1);
+
+  fts5StorageRenameOne(pConfig, &rc, "data", zName);
+  fts5StorageRenameOne(pConfig, &rc, "idx", zName);
+  fts5StorageRenameOne(pConfig, &rc, "config", zName);
+  if( pConfig->bColumnsize ){
+    fts5StorageRenameOne(pConfig, &rc, "docsize", zName);
+  }
+  if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
+    fts5StorageRenameOne(pConfig, &rc, "content", zName);
+  }
+  return rc;
+}
+
+/*
+** Create the shadow table named zPost, with definition zDefn. Return
+** SQLITE_OK if successful, or an SQLite error code otherwise.
+*/
+static int sqlite3Fts5CreateTable(
+  Fts5Config *pConfig,            /* FTS5 configuration */
+  const char *zPost,              /* Shadow table to create (e.g. "content") */
+  const char *zDefn,              /* Columns etc. for shadow table */
+  int bWithout,                   /* True for without rowid */
+  char **pzErr                    /* OUT: Error message */
+){
+  int rc;
+  char *zErr = 0;
+
+  rc = fts5ExecPrintf(pConfig->db, &zErr, "CREATE TABLE %Q.'%q_%q'(%s)%s",
+      pConfig->zDb, pConfig->zName, zPost, zDefn, bWithout?" WITHOUT ROWID":""
+  );
+  if( zErr ){
+    *pzErr = sqlite3_mprintf(
+        "fts5: error creating shadow table %q_%s: %s", 
+        pConfig->zName, zPost, zErr
+    );
+    sqlite3_free(zErr);
+  }
+
+  return rc;
+}
+
+/*
+** Open a new Fts5Index handle. If the bCreate argument is true, create
+** and initialize the underlying tables 
+**
+** If successful, set *pp to point to the new object and return SQLITE_OK.
+** Otherwise, set *pp to NULL and return an SQLite error code.
+*/
+static int sqlite3Fts5StorageOpen(
+  Fts5Config *pConfig, 
+  Fts5Index *pIndex, 
+  int bCreate, 
+  Fts5Storage **pp,
+  char **pzErr                    /* OUT: Error message */
+){
+  int rc = SQLITE_OK;
+  Fts5Storage *p;                 /* New object */
+  int nByte;                      /* Bytes of space to allocate */
+
+  nByte = sizeof(Fts5Storage)               /* Fts5Storage object */
+        + pConfig->nCol * sizeof(i64);      /* Fts5Storage.aTotalSize[] */
+  *pp = p = (Fts5Storage*)sqlite3_malloc(nByte);
+  if( !p ) return SQLITE_NOMEM;
+
+  memset(p, 0, nByte);
+  p->aTotalSize = (i64*)&p[1];
+  p->pConfig = pConfig;
+  p->pIndex = pIndex;
+
+  if( bCreate ){
+    if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
+      int nDefn = 32 + pConfig->nCol*10;
+      char *zDefn = sqlite3_malloc(32 + pConfig->nCol * 10);
+      if( zDefn==0 ){
+        rc = SQLITE_NOMEM;
+      }else{
+        int i;
+        int iOff;
+        sqlite3_snprintf(nDefn, zDefn, "id INTEGER PRIMARY KEY");
+        iOff = strlen(zDefn);
+        for(i=0; i<pConfig->nCol; i++){
+          sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i);
+          iOff += strlen(&zDefn[iOff]);
+        }
+        rc = sqlite3Fts5CreateTable(pConfig, "content", zDefn, 0, pzErr);
+      }
+      sqlite3_free(zDefn);
+    }
+
+    if( rc==SQLITE_OK && pConfig->bColumnsize ){
+      rc = sqlite3Fts5CreateTable(
+          pConfig, "docsize", "id INTEGER PRIMARY KEY, sz BLOB", 0, pzErr
+      );
+    }
+    if( rc==SQLITE_OK ){
+      rc = sqlite3Fts5CreateTable(
+          pConfig, "config", "k PRIMARY KEY, v", 1, pzErr
+      );
+    }
+    if( rc==SQLITE_OK ){
+      rc = sqlite3Fts5StorageConfigValue(p, "version", 0, FTS5_CURRENT_VERSION);
+    }
+  }
+
+  if( rc ){
+    sqlite3Fts5StorageClose(p);
+    *pp = 0;
+  }
+  return rc;
+}
+
+/*
+** Close a handle opened by an earlier call to sqlite3Fts5StorageOpen().
+*/
+static int sqlite3Fts5StorageClose(Fts5Storage *p){
+  int rc = SQLITE_OK;
+  if( p ){
+    int i;
+
+    /* Finalize all SQL statements */
+    for(i=0; i<ArraySize(p->aStmt); i++){
+      sqlite3_finalize(p->aStmt[i]);
+    }
+
+    sqlite3_free(p);
+  }
+  return rc;
+}
+
+typedef struct Fts5InsertCtx Fts5InsertCtx;
+struct Fts5InsertCtx {
+  Fts5Storage *pStorage;
+  int iCol;
+  int szCol;                      /* Size of column value in tokens */
+};
+
+/*
+** Tokenization callback used when inserting tokens into the FTS index.
+*/
+static int fts5StorageInsertCallback(
+  void *pContext,                 /* Pointer to Fts5InsertCtx object */
+  int tflags,
+  const char *pToken,             /* Buffer containing token */
+  int nToken,                     /* Size of token in bytes */
+  int iStart,                     /* Start offset of token */
+  int iEnd                        /* End offset of token */
+){
+  Fts5InsertCtx *pCtx = (Fts5InsertCtx*)pContext;
+  Fts5Index *pIdx = pCtx->pStorage->pIndex;
+  if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){
+    pCtx->szCol++;
+  }
+  return sqlite3Fts5IndexWrite(pIdx, pCtx->iCol, pCtx->szCol-1, pToken, nToken);
+}
+
+/*
+** If a row with rowid iDel is present in the %_content table, add the
+** delete-markers to the FTS index necessary to delete it. Do not actually
+** remove the %_content row at this time though.
+*/
+static int fts5StorageDeleteFromIndex(Fts5Storage *p, i64 iDel){
+  Fts5Config *pConfig = p->pConfig;
+  sqlite3_stmt *pSeek;            /* SELECT to read row iDel from %_data */
+  int rc;                         /* Return code */
+
+  rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0);
+  if( rc==SQLITE_OK ){
+    int rc2;
+    sqlite3_bind_int64(pSeek, 1, iDel);
+    if( sqlite3_step(pSeek)==SQLITE_ROW ){
+      int iCol;
+      Fts5InsertCtx ctx;
+      ctx.pStorage = p;
+      ctx.iCol = -1;
+      rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
+      for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
+        if( pConfig->abUnindexed[iCol-1] ) continue;
+        ctx.szCol = 0;
+        rc = sqlite3Fts5Tokenize(pConfig, 
+            FTS5_TOKENIZE_DOCUMENT,
+            (const char*)sqlite3_column_text(pSeek, iCol),
+            sqlite3_column_bytes(pSeek, iCol),
+            (void*)&ctx,
+            fts5StorageInsertCallback
+        );
+        p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
+      }
+      p->nTotalRow--;
+    }
+    rc2 = sqlite3_reset(pSeek);
+    if( rc==SQLITE_OK ) rc = rc2;
+  }
+
+  return rc;
+}
+
+
+/*
+** Insert a record into the %_docsize table. Specifically, do:
+**
+**   INSERT OR REPLACE INTO %_docsize(id, sz) VALUES(iRowid, pBuf);
+**
+** If there is no %_docsize table (as happens if the columnsize=0 option
+** is specified when the FTS5 table is created), this function is a no-op.
+*/
+static int fts5StorageInsertDocsize(
+  Fts5Storage *p,                 /* Storage module to write to */
+  i64 iRowid,                     /* id value */
+  Fts5Buffer *pBuf                /* sz value */
+){
+  int rc = SQLITE_OK;
+  if( p->pConfig->bColumnsize ){
+    sqlite3_stmt *pReplace = 0;
+    rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace, 0);
+    if( rc==SQLITE_OK ){
+      sqlite3_bind_int64(pReplace, 1, iRowid);
+      sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC);
+      sqlite3_step(pReplace);
+      rc = sqlite3_reset(pReplace);
+    }
+  }
+  return rc;
+}
+
+/*
+** Load the contents of the "averages" record from disk into the 
+** p->nTotalRow and p->aTotalSize[] variables. If successful, and if
+** argument bCache is true, set the p->bTotalsValid flag to indicate
+** that the contents of aTotalSize[] and nTotalRow are valid until
+** further notice.
+**
+** Return SQLITE_OK if successful, or an SQLite error code if an error
+** occurs.
+*/
+static int fts5StorageLoadTotals(Fts5Storage *p, int bCache){
+  int rc = SQLITE_OK;
+  if( p->bTotalsValid==0 ){
+    rc = sqlite3Fts5IndexGetAverages(p->pIndex, &p->nTotalRow, p->aTotalSize);
+    p->bTotalsValid = bCache;
+  }
+  return rc;
+}
+
+/*
+** Store the current contents of the p->nTotalRow and p->aTotalSize[] 
+** variables in the "averages" record on disk.
+**
+** Return SQLITE_OK if successful, or an SQLite error code if an error
+** occurs.
+*/
+static int fts5StorageSaveTotals(Fts5Storage *p){
+  int nCol = p->pConfig->nCol;
+  int i;
+  Fts5Buffer buf;
+  int rc = SQLITE_OK;
+  memset(&buf, 0, sizeof(buf));
+
+  sqlite3Fts5BufferAppendVarint(&rc, &buf, p->nTotalRow);
+  for(i=0; i<nCol; i++){
+    sqlite3Fts5BufferAppendVarint(&rc, &buf, p->aTotalSize[i]);
+  }
+  if( rc==SQLITE_OK ){
+    rc = sqlite3Fts5IndexSetAverages(p->pIndex, buf.p, buf.n);
+  }
+  sqlite3_free(buf.p);
+
+  return rc;
+}
+
+/*
+** Remove a row from the FTS table.
+*/
+static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel){
+  Fts5Config *pConfig = p->pConfig;
+  int rc;
+  sqlite3_stmt *pDel = 0;
+
+  rc = fts5StorageLoadTotals(p, 1);
+
+  /* Delete the index records */
+  if( rc==SQLITE_OK ){
+    rc = fts5StorageDeleteFromIndex(p, iDel);
+  }
+
+  /* Delete the %_docsize record */
+  if( rc==SQLITE_OK && pConfig->bColumnsize ){
+    rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0);
+    if( rc==SQLITE_OK ){
+      sqlite3_bind_int64(pDel, 1, iDel);
+      sqlite3_step(pDel);
+      rc = sqlite3_reset(pDel);
+    }
+  }
+
+  /* Delete the %_content record */
+  if( rc==SQLITE_OK ){
+    rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0);
+  }
+  if( rc==SQLITE_OK ){
+    sqlite3_bind_int64(pDel, 1, iDel);
+    sqlite3_step(pDel);
+    rc = sqlite3_reset(pDel);
+  }
+
+  /* Write the averages record */
+  if( rc==SQLITE_OK ){
+    rc = fts5StorageSaveTotals(p);
+  }
+
+  return rc;
+}
+
+static int sqlite3Fts5StorageSpecialDelete(
+  Fts5Storage *p, 
+  i64 iDel, 
+  sqlite3_value **apVal
+){
+  Fts5Config *pConfig = p->pConfig;
+  int rc;
+  sqlite3_stmt *pDel = 0;
+
+  assert( pConfig->eContent!=FTS5_CONTENT_NORMAL );
+  rc = fts5StorageLoadTotals(p, 1);
+
+  /* Delete the index records */
+  if( rc==SQLITE_OK ){
+    int iCol;
+    Fts5InsertCtx ctx;
+    ctx.pStorage = p;
+    ctx.iCol = -1;
+
+    rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
+    for(iCol=0; rc==SQLITE_OK && iCol<pConfig->nCol; iCol++){
+      if( pConfig->abUnindexed[iCol] ) continue;
+      ctx.szCol = 0;
+      rc = sqlite3Fts5Tokenize(pConfig, 
+        FTS5_TOKENIZE_DOCUMENT,
+        (const char*)sqlite3_value_text(apVal[iCol]),
+        sqlite3_value_bytes(apVal[iCol]),
+        (void*)&ctx,
+        fts5StorageInsertCallback
+      );
+      p->aTotalSize[iCol] -= (i64)ctx.szCol;
+    }
+    p->nTotalRow--;
+  }
+
+  /* Delete the %_docsize record */
+  if( pConfig->bColumnsize ){
+    if( rc==SQLITE_OK ){
+      rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0);
+    }
+    if( rc==SQLITE_OK ){
+      sqlite3_bind_int64(pDel, 1, iDel);
+      sqlite3_step(pDel);
+      rc = sqlite3_reset(pDel);
+    }
+  }
+
+  /* Write the averages record */
+  if( rc==SQLITE_OK ){
+    rc = fts5StorageSaveTotals(p);
+  }
+
+  return rc;
+}
+
+/*
+** Delete all entries in the FTS5 index.
+*/
+static int sqlite3Fts5StorageDeleteAll(Fts5Storage *p){
+  Fts5Config *pConfig = p->pConfig;
+  int rc;
+
+  /* Delete the contents of the %_data and %_docsize tables. */
+  rc = fts5ExecPrintf(pConfig->db, 0,
+      "DELETE FROM %Q.'%q_data';" 
+      "DELETE FROM %Q.'%q_idx';",
+      pConfig->zDb, pConfig->zName,
+      pConfig->zDb, pConfig->zName
+  );
+  if( rc==SQLITE_OK && pConfig->bColumnsize ){
+    rc = fts5ExecPrintf(pConfig->db, 0,
+        "DELETE FROM %Q.'%q_docsize';",
+        pConfig->zDb, pConfig->zName
+    );
+  }
+
+  /* Reinitialize the %_data table. This call creates the initial structure
+  ** and averages records.  */
+  if( rc==SQLITE_OK ){
+    rc = sqlite3Fts5IndexReinit(p->pIndex);
+  }
+  if( rc==SQLITE_OK ){
+    rc = sqlite3Fts5StorageConfigValue(p, "version", 0, FTS5_CURRENT_VERSION);
+  }
+  return rc;
+}
+
+static int sqlite3Fts5StorageRebuild(Fts5Storage *p){
+  Fts5Buffer buf = {0,0,0};
+  Fts5Config *pConfig = p->pConfig;
+  sqlite3_stmt *pScan = 0;
+  Fts5InsertCtx ctx;
+  int rc;
+
+  memset(&ctx, 0, sizeof(Fts5InsertCtx));
+  ctx.pStorage = p;
+  rc = sqlite3Fts5StorageDeleteAll(p);
+  if( rc==SQLITE_OK ){
+    rc = fts5StorageLoadTotals(p, 1);
+  }
+
+  if( rc==SQLITE_OK ){
+    rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0);
+  }
+
+  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pScan) ){
+    i64 iRowid = sqlite3_column_int64(pScan, 0);
+
+    sqlite3Fts5BufferZero(&buf);
+    rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
+    for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
+      ctx.szCol = 0;
+      if( pConfig->abUnindexed[ctx.iCol]==0 ){
+        rc = sqlite3Fts5Tokenize(pConfig, 
+            FTS5_TOKENIZE_DOCUMENT,
+            (const char*)sqlite3_column_text(pScan, ctx.iCol+1),
+            sqlite3_column_bytes(pScan, ctx.iCol+1),
+            (void*)&ctx,
+            fts5StorageInsertCallback
+        );
+      }
+      sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
+      p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
+    }
+    p->nTotalRow++;
+
+    if( rc==SQLITE_OK ){
+      rc = fts5StorageInsertDocsize(p, iRowid, &buf);
+    }
+  }
+  sqlite3_free(buf.p);
+
+  /* Write the averages record */
+  if( rc==SQLITE_OK ){
+    rc = fts5StorageSaveTotals(p);
+  }
+  return rc;
+}
+
+static int sqlite3Fts5StorageOptimize(Fts5Storage *p){
+  return sqlite3Fts5IndexOptimize(p->pIndex);
+}
+
+static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge){
+  return sqlite3Fts5IndexMerge(p->pIndex, nMerge);
+}
+
+/*
+** Allocate a new rowid. This is used for "external content" tables when
+** a NULL value is inserted into the rowid column. The new rowid is allocated
+** by inserting a dummy row into the %_docsize table. The dummy will be
+** overwritten later.
+**
+** If the %_docsize table does not exist, SQLITE_MISMATCH is returned. In
+** this case the user is required to provide a rowid explicitly.
+*/
+static int fts5StorageNewRowid(Fts5Storage *p, i64 *piRowid){
+  int rc = SQLITE_MISMATCH;
+  if( p->pConfig->bColumnsize ){
+    sqlite3_stmt *pReplace = 0;
+    rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace, 0);
+    if( rc==SQLITE_OK ){
+      sqlite3_bind_null(pReplace, 1);
+      sqlite3_bind_null(pReplace, 2);
+      sqlite3_step(pReplace);
+      rc = sqlite3_reset(pReplace);
+    }
+    if( rc==SQLITE_OK ){
+      *piRowid = sqlite3_last_insert_rowid(p->pConfig->db);
+    }
+  }
+  return rc;
+}
+
+/*
+** Insert a new row into the FTS content table.
+*/
+static int sqlite3Fts5StorageContentInsert(
+  Fts5Storage *p, 
+  sqlite3_value **apVal, 
+  i64 *piRowid
+){
+  Fts5Config *pConfig = p->pConfig;
+  int rc = SQLITE_OK;
+
+  /* Insert the new row into the %_content table. */
+  if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){
+    if( sqlite3_value_type(apVal[1])==SQLITE_INTEGER ){
+      *piRowid = sqlite3_value_int64(apVal[1]);
+    }else{
+      rc = fts5StorageNewRowid(p, piRowid);
+    }
+  }else{
+    sqlite3_stmt *pInsert = 0;    /* Statement to write %_content table */
+    int i;                        /* Counter variable */
+#if 0
+    if( eConflict==SQLITE_REPLACE ){
+      eStmt = FTS5_STMT_REPLACE_CONTENT;
+      rc = fts5StorageDeleteFromIndex(p, sqlite3_value_int64(apVal[1]));
+    }else{
+      eStmt = FTS5_STMT_INSERT_CONTENT;
+    }
+#endif
+    if( rc==SQLITE_OK ){
+      rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0);
+    }
+    for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
+      rc = sqlite3_bind_value(pInsert, i, apVal[i]);
+    }
+    if( rc==SQLITE_OK ){
+      sqlite3_step(pInsert);
+      rc = sqlite3_reset(pInsert);
+    }
+    *piRowid = sqlite3_last_insert_rowid(pConfig->db);
+  }
+
+  return rc;
+}
+
+/*
+** Insert new entries into the FTS index and %_docsize table.
+*/
+static int sqlite3Fts5StorageIndexInsert(
+  Fts5Storage *p, 
+  sqlite3_value **apVal, 
+  i64 iRowid
+){
+  Fts5Config *pConfig = p->pConfig;
+  int rc = SQLITE_OK;             /* Return code */
+  Fts5InsertCtx ctx;              /* Tokenization callback context object */
+  Fts5Buffer buf;                 /* Buffer used to build up %_docsize blob */
+
+  memset(&buf, 0, sizeof(Fts5Buffer));
+  ctx.pStorage = p;
+  rc = fts5StorageLoadTotals(p, 1);
+
+  if( rc==SQLITE_OK ){
+    rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
+  }
+  for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
+    ctx.szCol = 0;
+    if( pConfig->abUnindexed[ctx.iCol]==0 ){
+      rc = sqlite3Fts5Tokenize(pConfig, 
+          FTS5_TOKENIZE_DOCUMENT,
+          (const char*)sqlite3_value_text(apVal[ctx.iCol+2]),
+          sqlite3_value_bytes(apVal[ctx.iCol+2]),
+          (void*)&ctx,
+          fts5StorageInsertCallback
+      );
+    }
+    sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
+    p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
+  }
+  p->nTotalRow++;
+
+  /* Write the %_docsize record */
+  if( rc==SQLITE_OK ){
+    rc = fts5StorageInsertDocsize(p, iRowid, &buf);
+  }
+  sqlite3_free(buf.p);
+
+  /* Write the averages record */
+  if( rc==SQLITE_OK ){
+    rc = fts5StorageSaveTotals(p);
+  }
+
+  return rc;
+}
+
+static int fts5StorageCount(Fts5Storage *p, const char *zSuffix, i64 *pnRow){
+  Fts5Config *pConfig = p->pConfig;
+  char *zSql;
+  int rc;
+
+  zSql = sqlite3_mprintf("SELECT count(*) FROM %Q.'%q_%s'", 
+      pConfig->zDb, pConfig->zName, zSuffix
+  );
+  if( zSql==0 ){
+    rc = SQLITE_NOMEM;
+  }else{
+    sqlite3_stmt *pCnt = 0;
+    rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pCnt, 0);
+    if( rc==SQLITE_OK ){
+      if( SQLITE_ROW==sqlite3_step(pCnt) ){
+        *pnRow = sqlite3_column_int64(pCnt, 0);
+      }
+      rc = sqlite3_finalize(pCnt);
+    }
+  }
+
+  sqlite3_free(zSql);
+  return rc;
+}
+
+/*
+** Context object used by sqlite3Fts5StorageIntegrity().
+*/
+typedef struct Fts5IntegrityCtx Fts5IntegrityCtx;
+struct Fts5IntegrityCtx {
+  i64 iRowid;
+  int iCol;
+  int szCol;
+  u64 cksum;
+  Fts5Config *pConfig;
+};
+
+/*
+** Tokenization callback used by integrity check.
+*/
+static int fts5StorageIntegrityCallback(
+  void *pContext,                 /* Pointer to Fts5InsertCtx object */
+  int tflags,
+  const char *pToken,             /* Buffer containing token */
+  int nToken,                     /* Size of token in bytes */
+  int iStart,                     /* Start offset of token */
+  int iEnd                        /* End offset of token */
+){
+  Fts5IntegrityCtx *pCtx = (Fts5IntegrityCtx*)pContext;
+  if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){
+    pCtx->szCol++;
+  }
+  pCtx->cksum ^= sqlite3Fts5IndexCksum(
+      pCtx->pConfig, pCtx->iRowid, pCtx->iCol, pCtx->szCol-1, pToken, nToken
+  );
+  return SQLITE_OK;
+}
+
+/*
+** Check that the contents of the FTS index match that of the %_content
+** table. Return SQLITE_OK if they do, or SQLITE_CORRUPT if not. Return
+** some other SQLite error code if an error occurs while attempting to
+** determine this.
+*/
+static int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
+  Fts5Config *pConfig = p->pConfig;
+  int rc;                         /* Return code */
+  int *aColSize;                  /* Array of size pConfig->nCol */
+  i64 *aTotalSize;                /* Array of size pConfig->nCol */
+  Fts5IntegrityCtx ctx;
+  sqlite3_stmt *pScan;
+
+  memset(&ctx, 0, sizeof(Fts5IntegrityCtx));
+  ctx.pConfig = p->pConfig;
+  aTotalSize = (i64*)sqlite3_malloc(pConfig->nCol * (sizeof(int)+sizeof(i64)));
+  if( !aTotalSize ) return SQLITE_NOMEM;
+  aColSize = (int*)&aTotalSize[pConfig->nCol];
+  memset(aTotalSize, 0, sizeof(i64) * pConfig->nCol);
+
+  /* Generate the expected index checksum based on the contents of the
+  ** %_content table. This block stores the checksum in ctx.cksum. */
+  rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0);
+  if( rc==SQLITE_OK ){
+    int rc2;
+    while( SQLITE_ROW==sqlite3_step(pScan) ){
+      int i;
+      ctx.iRowid = sqlite3_column_int64(pScan, 0);
+      ctx.szCol = 0;
+      if( pConfig->bColumnsize ){
+        rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize);
+      }
+      for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
+        if( pConfig->abUnindexed[i] ) continue;
+        ctx.iCol = i;
+        ctx.szCol = 0;
+        rc = sqlite3Fts5Tokenize(pConfig, 
+            FTS5_TOKENIZE_DOCUMENT,
+            (const char*)sqlite3_column_text(pScan, i+1),
+            sqlite3_column_bytes(pScan, i+1),
+            (void*)&ctx,
+            fts5StorageIntegrityCallback
+        );
+        if( pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
+          rc = FTS5_CORRUPT;
+        }
+        aTotalSize[i] += ctx.szCol;
+      }
+      if( rc!=SQLITE_OK ) break;
+    }
+    rc2 = sqlite3_reset(pScan);
+    if( rc==SQLITE_OK ) rc = rc2;
+  }
+
+  /* Test that the "totals" (sometimes called "averages") record looks Ok */
+  if( rc==SQLITE_OK ){
+    int i;
+    rc = fts5StorageLoadTotals(p, 0);
+    for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
+      if( p->aTotalSize[i]!=aTotalSize[i] ) rc = FTS5_CORRUPT;
+    }
+  }
+
+  /* Check that the %_docsize and %_content tables contain the expected
+  ** number of rows.  */
+  if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
+    i64 nRow;
+    rc = fts5StorageCount(p, "content", &nRow);
+    if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT;
+  }
+  if( rc==SQLITE_OK && pConfig->bColumnsize ){
+    i64 nRow;
+    rc = fts5StorageCount(p, "docsize", &nRow);
+    if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT;
+  }
+
+  /* Pass the expected checksum down to the FTS index module. It will
+  ** verify, amongst other things, that it matches the checksum generated by
+  ** inspecting the index itself.  */
+  if( rc==SQLITE_OK ){
+    rc = sqlite3Fts5IndexIntegrityCheck(p->pIndex, ctx.cksum);
+  }
+
+  sqlite3_free(aTotalSize);
+  return rc;
+}
+
+/*
+** Obtain an SQLite statement handle that may be used to read data from the
+** %_content table.
+*/
+static int sqlite3Fts5StorageStmt(
+  Fts5Storage *p, 
+  int eStmt, 
+  sqlite3_stmt **pp, 
+  char **pzErrMsg
+){
+  int rc;
+  assert( eStmt==FTS5_STMT_SCAN_ASC 
+       || eStmt==FTS5_STMT_SCAN_DESC
+       || eStmt==FTS5_STMT_LOOKUP
+  );
+  rc = fts5StorageGetStmt(p, eStmt, pp, pzErrMsg);
+  if( rc==SQLITE_OK ){
+    assert( p->aStmt[eStmt]==*pp );
+    p->aStmt[eStmt] = 0;
+  }
+  return rc;
+}
+
+/*
+** Release an SQLite statement handle obtained via an earlier call to
+** sqlite3Fts5StorageStmt(). The eStmt parameter passed to this function
+** must match that passed to the sqlite3Fts5StorageStmt() call.
+*/
+static void sqlite3Fts5StorageStmtRelease(
+  Fts5Storage *p, 
+  int eStmt, 
+  sqlite3_stmt *pStmt
+){
+  assert( eStmt==FTS5_STMT_SCAN_ASC
+       || eStmt==FTS5_STMT_SCAN_DESC
+       || eStmt==FTS5_STMT_LOOKUP
+  );
+  if( p->aStmt[eStmt]==0 ){
+    sqlite3_reset(pStmt);
+    p->aStmt[eStmt] = pStmt;
+  }else{
+    sqlite3_finalize(pStmt);
+  }
+}
+
+static int fts5StorageDecodeSizeArray(
+  int *aCol, int nCol,            /* Array to populate */
+  const u8 *aBlob, int nBlob      /* Record to read varints from */
+){
+  int i;
+  int iOff = 0;
+  for(i=0; i<nCol; i++){
+    if( iOff>=nBlob ) return 1;
+    iOff += fts5GetVarint32(&aBlob[iOff], aCol[i]);
+  }
+  return (iOff!=nBlob);
+}
+
+/*
+** Argument aCol points to an array of integers containing one entry for
+** each table column. This function reads the %_docsize record for the
+** specified rowid and populates aCol[] with the results.
+**
+** An SQLite error code is returned if an error occurs, or SQLITE_OK
+** otherwise.
+*/
+static int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol){
+  int nCol = p->pConfig->nCol;    /* Number of user columns in table */
+  sqlite3_stmt *pLookup = 0;      /* Statement to query %_docsize */
+  int rc;                         /* Return Code */
+
+  assert( p->pConfig->bColumnsize );
+  rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP_DOCSIZE, &pLookup, 0);
+  if( rc==SQLITE_OK ){
+    int bCorrupt = 1;
+    sqlite3_bind_int64(pLookup, 1, iRowid);
+    if( SQLITE_ROW==sqlite3_step(pLookup) ){
+      const u8 *aBlob = sqlite3_column_blob(pLookup, 0);
+      int nBlob = sqlite3_column_bytes(pLookup, 0);
+      if( 0==fts5StorageDecodeSizeArray(aCol, nCol, aBlob, nBlob) ){
+        bCorrupt = 0;
+      }
+    }
+    rc = sqlite3_reset(pLookup);
+    if( bCorrupt && rc==SQLITE_OK ){
+      rc = FTS5_CORRUPT;
+    }
+  }
+
+  return rc;
+}
+
+static int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnToken){
+  int rc = fts5StorageLoadTotals(p, 0);
+  if( rc==SQLITE_OK ){
+    *pnToken = 0;
+    if( iCol<0 ){
+      int i;
+      for(i=0; i<p->pConfig->nCol; i++){
+        *pnToken += p->aTotalSize[i];
+      }
+    }else if( iCol<p->pConfig->nCol ){
+      *pnToken = p->aTotalSize[iCol];
+    }else{
+      rc = SQLITE_RANGE;
+    }
+  }
+  return rc;
+}
+
+static int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow){
+  int rc = fts5StorageLoadTotals(p, 0);
+  if( rc==SQLITE_OK ){
+    *pnRow = p->nTotalRow;
+  }
+  return rc;
+}
+
+/*
+** Flush any data currently held in-memory to disk.
+*/
+static int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit){
+  if( bCommit && p->bTotalsValid ){
+    int rc = fts5StorageSaveTotals(p);
+    p->bTotalsValid = 0;
+    if( rc!=SQLITE_OK ) return rc;
+  }
+  return sqlite3Fts5IndexSync(p->pIndex, bCommit);
+}
+
+static int sqlite3Fts5StorageRollback(Fts5Storage *p){
+  p->bTotalsValid = 0;
+  return sqlite3Fts5IndexRollback(p->pIndex);
+}
+
+static int sqlite3Fts5StorageConfigValue(
+  Fts5Storage *p, 
+  const char *z,
+  sqlite3_value *pVal,
+  int iVal
+){
+  sqlite3_stmt *pReplace = 0;
+  int rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_CONFIG, &pReplace, 0);
+  if( rc==SQLITE_OK ){
+    sqlite3_bind_text(pReplace, 1, z, -1, SQLITE_STATIC);
+    if( pVal ){
+      sqlite3_bind_value(pReplace, 2, pVal);
+    }else{
+      sqlite3_bind_int(pReplace, 2, iVal);
+    }
+    sqlite3_step(pReplace);
+    rc = sqlite3_reset(pReplace);
+  }
+  if( rc==SQLITE_OK && pVal ){
+    int iNew = p->pConfig->iCookie + 1;
+    rc = sqlite3Fts5IndexSetCookie(p->pIndex, iNew);
+    if( rc==SQLITE_OK ){
+      p->pConfig->iCookie = iNew;
+    }
+  }
+  return rc;
+}
+
+
+
+/*
+** 2014 May 31
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+******************************************************************************
+*/
+
+
+
+/**************************************************************************
+** Start of ascii tokenizer implementation.
+*/
+
+/*
+** For tokenizers with no "unicode" modifier, the set of token characters
+** is the same as the set of ASCII range alphanumeric characters. 
+*/
+static unsigned char aAsciiTokenChar[128] = {
+  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,   /* 0x00..0x0F */
+  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,   /* 0x10..0x1F */
+  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,   /* 0x20..0x2F */
+  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 0, 0, 0, 0, 0, 0,   /* 0x30..0x3F */
+  0, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   /* 0x40..0x4F */
+  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 0, 0, 0, 0, 0,   /* 0x50..0x5F */
+  0, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   /* 0x60..0x6F */
+  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 0, 0, 0, 0, 0,   /* 0x70..0x7F */
+};
+
+typedef struct AsciiTokenizer AsciiTokenizer;
+struct AsciiTokenizer {
+  unsigned char aTokenChar[128];
+};
+
+static void fts5AsciiAddExceptions(
+  AsciiTokenizer *p, 
+  const char *zArg, 
+  int bTokenChars
+){
+  int i;
+  for(i=0; zArg[i]; i++){
+    if( (zArg[i] & 0x80)==0 ){
+      p->aTokenChar[(int)zArg[i]] = (unsigned char)bTokenChars;
+    }
+  }
+}
+
+/*
+** Delete a "ascii" tokenizer.
+*/
+static void fts5AsciiDelete(Fts5Tokenizer *p){
+  sqlite3_free(p);
+}
+
+/*
+** Create an "ascii" tokenizer.
+*/
+static int fts5AsciiCreate(
+  void *pCtx, 
+  const char **azArg, int nArg,
+  Fts5Tokenizer **ppOut
+){
+  int rc = SQLITE_OK;
+  AsciiTokenizer *p = 0;
+  if( nArg%2 ){
+    rc = SQLITE_ERROR;
+  }else{
+    p = sqlite3_malloc(sizeof(AsciiTokenizer));
+    if( p==0 ){
+      rc = SQLITE_NOMEM;
+    }else{
+      int i;
+      memset(p, 0, sizeof(AsciiTokenizer));
+      memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar));
+      for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
+        const char *zArg = azArg[i+1];
+        if( 0==sqlite3_stricmp(azArg[i], "tokenchars") ){
+          fts5AsciiAddExceptions(p, zArg, 1);
+        }else
+        if( 0==sqlite3_stricmp(azArg[i], "separators") ){
+          fts5AsciiAddExceptions(p, zArg, 0);
+        }else{
+          rc = SQLITE_ERROR;
+        }
+      }
+      if( rc!=SQLITE_OK ){
+        fts5AsciiDelete((Fts5Tokenizer*)p);
+        p = 0;
+      }
+    }
+  }
+
+  *ppOut = (Fts5Tokenizer*)p;
+  return rc;
+}
+
+
+static void asciiFold(char *aOut, const char *aIn, int nByte){
+  int i;
+  for(i=0; i<nByte; i++){
+    char c = aIn[i];
+    if( c>='A' && c<='Z' ) c += 32;
+    aOut[i] = c;
+  }
+}
+
+/*
+** Tokenize some text using the ascii tokenizer.
+*/
+static int fts5AsciiTokenize(
+  Fts5Tokenizer *pTokenizer,
+  void *pCtx,
+  int flags,
+  const char *pText, int nText,
+  int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd)
+){
+  AsciiTokenizer *p = (AsciiTokenizer*)pTokenizer;
+  int rc = SQLITE_OK;
+  int ie;
+  int is = 0;
+
+  char aFold[64];
+  int nFold = sizeof(aFold);
+  char *pFold = aFold;
+  unsigned char *a = p->aTokenChar;
+
+  while( is<nText && rc==SQLITE_OK ){
+    int nByte;
+
+    /* Skip any leading divider characters. */
+    while( is<nText && ((pText[is]&0x80)==0 && a[(int)pText[is]]==0) ){
+      is++;
+    }
+    if( is==nText ) break;
+
+    /* Count the token characters */
+    ie = is+1;
+    while( ie<nText && ((pText[ie]&0x80) || a[(int)pText[ie]] ) ){
+      ie++;
+    }
+
+    /* Fold to lower case */
+    nByte = ie-is;
+    if( nByte>nFold ){
+      if( pFold!=aFold ) sqlite3_free(pFold);
+      pFold = sqlite3_malloc(nByte*2);
+      if( pFold==0 ){
+        rc = SQLITE_NOMEM;
+        break;
+      }
+      nFold = nByte*2;
+    }
+    asciiFold(pFold, &pText[is], nByte);
+
+    /* Invoke the token callback */
+    rc = xToken(pCtx, 0, pFold, nByte, is, ie);
+    is = ie+1;
+  }
+  
+  if( pFold!=aFold ) sqlite3_free(pFold);
+  if( rc==SQLITE_DONE ) rc = SQLITE_OK;
+  return rc;
+}
+
+/**************************************************************************
+** Start of unicode61 tokenizer implementation.
+*/
+
+
+/*
+** The following two macros - READ_UTF8 and WRITE_UTF8 - have been copied
+** from the sqlite3 source file utf.c. If this file is compiled as part
+** of the amalgamation, they are not required.
+*/
+#ifndef SQLITE_AMALGAMATION
+
+static const unsigned char sqlite3Utf8Trans1[] = {
+  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+  0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+  0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
+};
+
+#define READ_UTF8(zIn, zTerm, c)                           \
+  c = *(zIn++);                                            \
+  if( c>=0xc0 ){                                           \
+    c = sqlite3Utf8Trans1[c-0xc0];                         \
+    while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){            \
+      c = (c<<6) + (0x3f & *(zIn++));                      \
+    }                                                      \
+    if( c<0x80                                             \
+        || (c&0xFFFFF800)==0xD800                          \
+        || (c&0xFFFFFFFE)==0xFFFE ){  c = 0xFFFD; }        \
+  }
+
+
+#define WRITE_UTF8(zOut, c) {                          \
+  if( c<0x00080 ){                                     \
+    *zOut++ = (unsigned char)(c&0xFF);                 \
+  }                                                    \
+  else if( c<0x00800 ){                                \
+    *zOut++ = 0xC0 + (unsigned char)((c>>6)&0x1F);     \
+    *zOut++ = 0x80 + (unsigned char)(c & 0x3F);        \
+  }                                                    \
+  else if( c<0x10000 ){                                \
+    *zOut++ = 0xE0 + (unsigned char)((c>>12)&0x0F);    \
+    *zOut++ = 0x80 + (unsigned char)((c>>6) & 0x3F);   \
+    *zOut++ = 0x80 + (unsigned char)(c & 0x3F);        \
+  }else{                                               \
+    *zOut++ = 0xF0 + (unsigned char)((c>>18) & 0x07);  \
+    *zOut++ = 0x80 + (unsigned char)((c>>12) & 0x3F);  \
+    *zOut++ = 0x80 + (unsigned char)((c>>6) & 0x3F);   \
+    *zOut++ = 0x80 + (unsigned char)(c & 0x3F);        \
+  }                                                    \
+}
+
+#endif /* ifndef SQLITE_AMALGAMATION */
+
+typedef struct Unicode61Tokenizer Unicode61Tokenizer;
+struct Unicode61Tokenizer {
+  unsigned char aTokenChar[128];  /* ASCII range token characters */
+  char *aFold;                    /* Buffer to fold text into */
+  int nFold;                      /* Size of aFold[] in bytes */
+  int bRemoveDiacritic;           /* True if remove_diacritics=1 is set */
+  int nException;
+  int *aiException;
+};
+
+static int fts5UnicodeAddExceptions(
+  Unicode61Tokenizer *p,          /* Tokenizer object */
+  const char *z,                  /* Characters to treat as exceptions */
+  int bTokenChars                 /* 1 for 'tokenchars', 0 for 'separators' */
+){
+  int rc = SQLITE_OK;
+  int n = strlen(z);
+  int *aNew;
+
+  if( n>0 ){
+    aNew = (int*)sqlite3_realloc(p->aiException, (n+p->nException)*sizeof(int));
+    if( aNew ){
+      int nNew = p->nException;
+      const unsigned char *zCsr = (const unsigned char*)z;
+      const unsigned char *zTerm = (const unsigned char*)&z[n];
+      while( zCsr<zTerm ){
+        int iCode;
+        int bToken;
+        READ_UTF8(zCsr, zTerm, iCode);
+        if( iCode<128 ){
+          p->aTokenChar[iCode] = bTokenChars;
+        }else{
+          bToken = sqlite3Fts5UnicodeIsalnum(iCode);
+          assert( (bToken==0 || bToken==1) ); 
+          assert( (bTokenChars==0 || bTokenChars==1) );
+          if( bToken!=bTokenChars && sqlite3Fts5UnicodeIsdiacritic(iCode)==0 ){
+            int i;
+            for(i=0; i<nNew; i++){
+              if( aNew[i]>iCode ) break;
+            }
+            memmove(&aNew[i+1], &aNew[i], (nNew-i)*sizeof(int));
+            aNew[i] = iCode;
+            nNew++;
+          }
+        }
+      }
+      p->aiException = aNew;
+      p->nException = nNew;
+    }else{
+      rc = SQLITE_NOMEM;
+    }
+  }
+
+  return rc;
+}
+
+/*
+** Return true if the p->aiException[] array contains the value iCode.
+*/
+static int fts5UnicodeIsException(Unicode61Tokenizer *p, int iCode){
+  if( p->nException>0 ){
+    int *a = p->aiException;
+    int iLo = 0;
+    int iHi = p->nException-1;
+
+    while( iHi>=iLo ){
+      int iTest = (iHi + iLo) / 2;
+      if( iCode==a[iTest] ){
+        return 1;
+      }else if( iCode>a[iTest] ){
+        iLo = iTest+1;
+      }else{
+        iHi = iTest-1;
+      }
+    }
+  }
+
+  return 0;
+}
+
+/*
+** Delete a "unicode61" tokenizer.
+*/
+static void fts5UnicodeDelete(Fts5Tokenizer *pTok){
+  if( pTok ){
+    Unicode61Tokenizer *p = (Unicode61Tokenizer*)pTok;
+    sqlite3_free(p->aiException);
+    sqlite3_free(p->aFold);
+    sqlite3_free(p);
+  }
+  return;
+}
+
+/*
+** Create a "unicode61" tokenizer.
+*/
+static int fts5UnicodeCreate(
+  void *pCtx, 
+  const char **azArg, int nArg,
+  Fts5Tokenizer **ppOut
+){
+  int rc = SQLITE_OK;             /* Return code */
+  Unicode61Tokenizer *p = 0;      /* New tokenizer object */ 
+
+  if( nArg%2 ){
+    rc = SQLITE_ERROR;
+  }else{
+    p = (Unicode61Tokenizer*)sqlite3_malloc(sizeof(Unicode61Tokenizer));
+    if( p ){
+      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;
+      }
+      for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
+        const char *zArg = azArg[i+1];
+        if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
+          if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){
+            rc = SQLITE_ERROR;
+          }
+          p->bRemoveDiacritic = (zArg[0]=='1');
+        }else
+        if( 0==sqlite3_stricmp(azArg[i], "tokenchars") ){
+          rc = fts5UnicodeAddExceptions(p, zArg, 1);
+        }else
+        if( 0==sqlite3_stricmp(azArg[i], "separators") ){
+          rc = fts5UnicodeAddExceptions(p, zArg, 0);
+        }else{
+          rc = SQLITE_ERROR;
+        }
+      }
+    }else{
+      rc = SQLITE_NOMEM;
+    }
+    if( rc!=SQLITE_OK ){
+      fts5UnicodeDelete((Fts5Tokenizer*)p);
+      p = 0;
+    }
+    *ppOut = (Fts5Tokenizer*)p;
+  }
+  return rc;
+}
+
+/*
+** Return true if, for the purposes of tokenizing with the tokenizer
+** passed as the first argument, codepoint iCode is considered a token 
+** character (not a separator).
+*/
+static int fts5UnicodeIsAlnum(Unicode61Tokenizer *p, int iCode){
+  assert( (sqlite3Fts5UnicodeIsalnum(iCode) & 0xFFFFFFFE)==0 );
+  return sqlite3Fts5UnicodeIsalnum(iCode) ^ fts5UnicodeIsException(p, iCode);
+}
+
+static int fts5UnicodeTokenize(
+  Fts5Tokenizer *pTokenizer,
+  void *pCtx,
+  int flags,
+  const char *pText, int nText,
+  int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd)
+){
+  Unicode61Tokenizer *p = (Unicode61Tokenizer*)pTokenizer;
+  int rc = SQLITE_OK;
+  unsigned char *a = p->aTokenChar;
+
+  unsigned char *zTerm = (unsigned char*)&pText[nText];
+  unsigned char *zCsr = (unsigned char *)pText;
+
+  /* Output buffer */
+  char *aFold = p->aFold;
+  int nFold = p->nFold;
+  const char *pEnd = &aFold[nFold-6];
+
+  /* Each iteration of this loop gobbles up a contiguous run of separators,
+  ** then the next token.  */
+  while( rc==SQLITE_OK ){
+    int iCode;                    /* non-ASCII codepoint read from input */
+    char *zOut = aFold;
+    int is;
+    int ie;
+
+    /* Skip any separator characters. */
+    while( 1 ){
+      if( zCsr>=zTerm ) goto tokenize_done;
+      if( *zCsr & 0x80 ) {
+        /* A character outside of the ascii range. Skip past it if it is
+        ** a separator character. Or break out of the loop if it is not. */
+        is = zCsr - (unsigned char*)pText;
+        READ_UTF8(zCsr, zTerm, iCode);
+        if( fts5UnicodeIsAlnum(p, iCode) ){
+          goto non_ascii_tokenchar;
+        }
+      }else{
+        if( a[*zCsr] ){
+          is = zCsr - (unsigned char*)pText;
+          goto ascii_tokenchar;
+        }
+        zCsr++;
+      }
+    }
+
+    /* Run through the tokenchars. Fold them into the output buffer along
+    ** the way.  */
+    while( zCsr<zTerm ){
+
+      /* Grow the output buffer so that there is sufficient space to fit the
+      ** largest possible utf-8 character.  */
+      if( zOut>pEnd ){
+        aFold = sqlite3_malloc(nFold*2);
+        if( aFold==0 ){
+          rc = SQLITE_NOMEM;
+          goto tokenize_done;
+        }
+        zOut = &aFold[zOut - p->aFold];
+        memcpy(aFold, p->aFold, nFold);
+        sqlite3_free(p->aFold);
+        p->aFold = aFold;
+        p->nFold = nFold = nFold*2;
+        pEnd = &aFold[nFold-6];
+      }
+
+      if( *zCsr & 0x80 ){
+        /* An non-ascii-range character. Fold it into the output buffer if
+        ** it is a token character, or break out of the loop if it is not. */
+        READ_UTF8(zCsr, zTerm, iCode);
+        if( fts5UnicodeIsAlnum(p,iCode)||sqlite3Fts5UnicodeIsdiacritic(iCode) ){
+ non_ascii_tokenchar:
+          iCode = sqlite3Fts5UnicodeFold(iCode, p->bRemoveDiacritic);
+          if( iCode ) WRITE_UTF8(zOut, iCode);
+        }else{
+          break;
+        }
+      }else if( a[*zCsr]==0 ){
+        /* An ascii-range separator character. End of token. */
+        break; 
+      }else{
+ ascii_tokenchar:
+        if( *zCsr>='A' && *zCsr<='Z' ){
+          *zOut++ = *zCsr + 32;
+        }else{
+          *zOut++ = *zCsr;
+        }
+        zCsr++;
+      }
+      ie = zCsr - (unsigned char*)pText;
+    }
+
+    /* Invoke the token callback */
+    rc = xToken(pCtx, 0, aFold, zOut-aFold, is, ie); 
+  }
+  
+ tokenize_done:
+  if( rc==SQLITE_DONE ) rc = SQLITE_OK;
+  return rc;
+}
+
+/**************************************************************************
+** Start of porter stemmer implementation.
+*/
+
+/* Any tokens larger than this (in bytes) are passed through without
+** stemming. */
+#define FTS5_PORTER_MAX_TOKEN 64
+
+typedef struct PorterTokenizer PorterTokenizer;
+struct PorterTokenizer {
+  fts5_tokenizer tokenizer;       /* Parent tokenizer module */
+  Fts5Tokenizer *pTokenizer;      /* Parent tokenizer instance */
+  char aBuf[FTS5_PORTER_MAX_TOKEN + 64];
+};
+
+/*
+** Delete a "porter" tokenizer.
+*/
+static void fts5PorterDelete(Fts5Tokenizer *pTok){
+  if( pTok ){
+    PorterTokenizer *p = (PorterTokenizer*)pTok;
+    if( p->pTokenizer ){
+      p->tokenizer.xDelete(p->pTokenizer);
+    }
+    sqlite3_free(p);
+  }
+}
+
+/*
+** Create a "porter" tokenizer.
+*/
+static int fts5PorterCreate(
+  void *pCtx, 
+  const char **azArg, int nArg,
+  Fts5Tokenizer **ppOut
+){
+  fts5_api *pApi = (fts5_api*)pCtx;
+  int rc = SQLITE_OK;
+  PorterTokenizer *pRet;
+  void *pUserdata = 0;
+  const char *zBase = "unicode61";
+
+  if( nArg>0 ){
+    zBase = azArg[0];
+  }
+
+  pRet = (PorterTokenizer*)sqlite3_malloc(sizeof(PorterTokenizer));
+  if( pRet ){
+    memset(pRet, 0, sizeof(PorterTokenizer));
+    rc = pApi->xFindTokenizer(pApi, zBase, &pUserdata, &pRet->tokenizer);
+  }else{
+    rc = SQLITE_NOMEM;
+  }
+  if( rc==SQLITE_OK ){
+    int nArg2 = (nArg>0 ? nArg-1 : 0);
+    const char **azArg2 = (nArg2 ? &azArg[1] : 0);
+    rc = pRet->tokenizer.xCreate(pUserdata, azArg2, nArg2, &pRet->pTokenizer);
+  }
+
+  if( rc!=SQLITE_OK ){
+    fts5PorterDelete((Fts5Tokenizer*)pRet);
+    pRet = 0;
+  }
+  *ppOut = (Fts5Tokenizer*)pRet;
+  return rc;
+}
+
+typedef struct PorterContext PorterContext;
+struct PorterContext {
+  void *pCtx;
+  int (*xToken)(void*, int, const char*, int, int, int);
+  char *aBuf;
+};
+
+typedef struct PorterRule PorterRule;
+struct PorterRule {
+  const char *zSuffix;
+  int nSuffix;
+  int (*xCond)(char *zStem, int nStem);
+  const char *zOutput;
+  int nOutput;
+};
+
+#if 0
+static int fts5PorterApply(char *aBuf, int *pnBuf, PorterRule *aRule){
+  int ret = -1;
+  int nBuf = *pnBuf;
+  PorterRule *p;
+
+  for(p=aRule; p->zSuffix; p++){
+    assert( strlen(p->zSuffix)==p->nSuffix );
+    assert( strlen(p->zOutput)==p->nOutput );
+    if( nBuf<p->nSuffix ) continue;
+    if( 0==memcmp(&aBuf[nBuf - p->nSuffix], p->zSuffix, p->nSuffix) ) break;
+  }
+
+  if( p->zSuffix ){
+    int nStem = nBuf - p->nSuffix;
+    if( p->xCond==0 || p->xCond(aBuf, nStem) ){
+      memcpy(&aBuf[nStem], p->zOutput, p->nOutput);
+      *pnBuf = nStem + p->nOutput;
+      ret = p - aRule;
+    }
+  }
+
+  return ret;
+}
+#endif
+
+static int fts5PorterIsVowel(char c, int bYIsVowel){
+  return (
+      c=='a' || c=='e' || c=='i' || c=='o' || c=='u' || (bYIsVowel && c=='y')
+  );
+}
+
+static int fts5PorterGobbleVC(char *zStem, int nStem, int bPrevCons){
+  int i;
+  int bCons = bPrevCons;
+
+  /* Scan for a vowel */
+  for(i=0; i<nStem; i++){
+    if( 0==(bCons = !fts5PorterIsVowel(zStem[i], bCons)) ) break;
+  }
+
+  /* Scan for a consonent */
+  for(i++; i<nStem; i++){
+    if( (bCons = !fts5PorterIsVowel(zStem[i], bCons)) ) return i+1;
+  }
+  return 0;
+}
+
+/* porter rule condition: (m > 0) */
+static int fts5Porter_MGt0(char *zStem, int nStem){
+  return !!fts5PorterGobbleVC(zStem, nStem, 0);
+}
+
+/* porter rule condition: (m > 1) */
+static int fts5Porter_MGt1(char *zStem, int nStem){
+  int n;
+  n = fts5PorterGobbleVC(zStem, nStem, 0);
+  if( n && fts5PorterGobbleVC(&zStem[n], nStem-n, 1) ){
+    return 1;
+  }
+  return 0;
+}
+
+/* porter rule condition: (m = 1) */
+static int fts5Porter_MEq1(char *zStem, int nStem){
+  int n;
+  n = fts5PorterGobbleVC(zStem, nStem, 0);
+  if( n && 0==fts5PorterGobbleVC(&zStem[n], nStem-n, 1) ){
+    return 1;
+  }
+  return 0;
+}
+
+/* porter rule condition: (*o) */
+static int fts5Porter_Ostar(char *zStem, int nStem){
+  if( zStem[nStem-1]=='w' || zStem[nStem-1]=='x' || zStem[nStem-1]=='y' ){
+    return 0;
+  }else{
+    int i;
+    int mask = 0;
+    int bCons = 0;
+    for(i=0; i<nStem; i++){
+      bCons = !fts5PorterIsVowel(zStem[i], bCons);
+      assert( bCons==0 || bCons==1 );
+      mask = (mask << 1) + bCons;
+    }
+    return ((mask & 0x0007)==0x0005);
+  }
+}
+
+/* porter rule condition: (m > 1 and (*S or *T)) */
+static int fts5Porter_MGt1_and_S_or_T(char *zStem, int nStem){
+  assert( nStem>0 );
+  return (zStem[nStem-1]=='s' || zStem[nStem-1]=='t') 
+      && fts5Porter_MGt1(zStem, nStem);
+}
+
+/* porter rule condition: (*v*) */
+static int fts5Porter_Vowel(char *zStem, int nStem){
+  int i;
+  for(i=0; i<nStem; i++){
+    if( fts5PorterIsVowel(zStem[i], i>0) ){
+      return 1;
+    }
+  }
+  return 0;
+}
+
+
+/**************************************************************************
+***************************************************************************
+** GENERATED CODE STARTS HERE (mkportersteps.tcl)
+*/
+
+static int fts5PorterStep4(char *aBuf, int *pnBuf){
+  int ret = 0;
+  int nBuf = *pnBuf;
+  switch( aBuf[nBuf-2] ){
+    
+    case 'a': 
+      if( nBuf>2 && 0==memcmp("al", &aBuf[nBuf-2], 2) ){
+        if( fts5Porter_MGt1(aBuf, nBuf-2) ){
+          *pnBuf = nBuf - 2;
+        }
+      }
+      break;
+  
+    case 'c': 
+      if( nBuf>4 && 0==memcmp("ance", &aBuf[nBuf-4], 4) ){
+        if( fts5Porter_MGt1(aBuf, nBuf-4) ){
+          *pnBuf = nBuf - 4;
+        }
+      }else if( nBuf>4 && 0==memcmp("ence", &aBuf[nBuf-4], 4) ){
+        if( fts5Porter_MGt1(aBuf, nBuf-4) ){
+          *pnBuf = nBuf - 4;
+        }
+      }
+      break;
+  
+    case 'e': 
+      if( nBuf>2 && 0==memcmp("er", &aBuf[nBuf-2], 2) ){
+        if( fts5Porter_MGt1(aBuf, nBuf-2) ){
+          *pnBuf = nBuf - 2;
+        }
+      }
+      break;
+  
+    case 'i': 
+      if( nBuf>2 && 0==memcmp("ic", &aBuf[nBuf-2], 2) ){
+        if( fts5Porter_MGt1(aBuf, nBuf-2) ){
+          *pnBuf = nBuf - 2;
+        }
+      }
+      break;
+  
+    case 'l': 
+      if( nBuf>4 && 0==memcmp("able", &aBuf[nBuf-4], 4) ){
+        if( fts5Porter_MGt1(aBuf, nBuf-4) ){
+          *pnBuf = nBuf - 4;
+        }
+      }else if( nBuf>4 && 0==memcmp("ible", &aBuf[nBuf-4], 4) ){
+        if( fts5Porter_MGt1(aBuf, nBuf-4) ){
+          *pnBuf = nBuf - 4;
+        }
+      }
+      break;
+  
+    case 'n': 
+      if( nBuf>3 && 0==memcmp("ant", &aBuf[nBuf-3], 3) ){
+        if( fts5Porter_MGt1(aBuf, nBuf-3) ){
+          *pnBuf = nBuf - 3;
+        }
+      }else if( nBuf>5 && 0==memcmp("ement", &aBuf[nBuf-5], 5) ){
+        if( fts5Porter_MGt1(aBuf, nBuf-5) ){
+          *pnBuf = nBuf - 5;
+        }
+      }else if( nBuf>4 && 0==memcmp("ment", &aBuf[nBuf-4], 4) ){
+        if( fts5Porter_MGt1(aBuf, nBuf-4) ){
+          *pnBuf = nBuf - 4;
+        }
+      }else if( nBuf>3 && 0==memcmp("ent", &aBuf[nBuf-3], 3) ){
+        if( fts5Porter_MGt1(aBuf, nBuf-3) ){
+          *pnBuf = nBuf - 3;
+        }
+      }
+      break;
+  
+    case 'o': 
+      if( nBuf>3 && 0==memcmp("ion", &aBuf[nBuf-3], 3) ){
+        if( fts5Porter_MGt1_and_S_or_T(aBuf, nBuf-3) ){
+          *pnBuf = nBuf - 3;
+        }
+      }else if( nBuf>2 && 0==memcmp("ou", &aBuf[nBuf-2], 2) ){
+        if( fts5Porter_MGt1(aBuf, nBuf-2) ){
+          *pnBuf = nBuf - 2;
+        }
+      }
+      break;
+  
+    case 's': 
+      if( nBuf>3 && 0==memcmp("ism", &aBuf[nBuf-3], 3) ){
+        if( fts5Porter_MGt1(aBuf, nBuf-3) ){
+          *pnBuf = nBuf - 3;
+        }
+      }
+      break;
+  
+    case 't': 
+      if( nBuf>3 && 0==memcmp("ate", &aBuf[nBuf-3], 3) ){
+        if( fts5Porter_MGt1(aBuf, nBuf-3) ){
+          *pnBuf = nBuf - 3;
+        }
+      }else if( nBuf>3 && 0==memcmp("iti", &aBuf[nBuf-3], 3) ){
+        if( fts5Porter_MGt1(aBuf, nBuf-3) ){
+          *pnBuf = nBuf - 3;
+        }
+      }
+      break;
+  
+    case 'u': 
+      if( nBuf>3 && 0==memcmp("ous", &aBuf[nBuf-3], 3) ){
+        if( fts5Porter_MGt1(aBuf, nBuf-3) ){
+          *pnBuf = nBuf - 3;
+        }
+      }
+      break;
+  
+    case 'v': 
+      if( nBuf>3 && 0==memcmp("ive", &aBuf[nBuf-3], 3) ){
+        if( fts5Porter_MGt1(aBuf, nBuf-3) ){
+          *pnBuf = nBuf - 3;
+        }
+      }
+      break;
+  
+    case 'z': 
+      if( nBuf>3 && 0==memcmp("ize", &aBuf[nBuf-3], 3) ){
+        if( fts5Porter_MGt1(aBuf, nBuf-3) ){
+          *pnBuf = nBuf - 3;
+        }
+      }
+      break;
+  
+  }
+  return ret;
+}
+  
+
+static int fts5PorterStep1B2(char *aBuf, int *pnBuf){
+  int ret = 0;
+  int nBuf = *pnBuf;
+  switch( aBuf[nBuf-2] ){
+    
+    case 'a': 
+      if( nBuf>2 && 0==memcmp("at", &aBuf[nBuf-2], 2) ){
+        memcpy(&aBuf[nBuf-2], "ate", 3);
+        *pnBuf = nBuf - 2 + 3;
+        ret = 1;
+      }
+      break;
+  
+    case 'b': 
+      if( nBuf>2 && 0==memcmp("bl", &aBuf[nBuf-2], 2) ){
+        memcpy(&aBuf[nBuf-2], "ble", 3);
+        *pnBuf = nBuf - 2 + 3;
+        ret = 1;
+      }
+      break;
+  
+    case 'i': 
+      if( nBuf>2 && 0==memcmp("iz", &aBuf[nBuf-2], 2) ){
+        memcpy(&aBuf[nBuf-2], "ize", 3);
+        *pnBuf = nBuf - 2 + 3;
+        ret = 1;
+      }
+      break;
+  
+  }
+  return ret;
+}
+  
+
+static int fts5PorterStep2(char *aBuf, int *pnBuf){
+  int ret = 0;
+  int nBuf = *pnBuf;
+  switch( aBuf[nBuf-2] ){
+    
+    case 'a': 
+      if( nBuf>7 && 0==memcmp("ational", &aBuf[nBuf-7], 7) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-7) ){
+          memcpy(&aBuf[nBuf-7], "ate", 3);
+          *pnBuf = nBuf - 7 + 3;
+        }
+      }else if( nBuf>6 && 0==memcmp("tional", &aBuf[nBuf-6], 6) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-6) ){
+          memcpy(&aBuf[nBuf-6], "tion", 4);
+          *pnBuf = nBuf - 6 + 4;
+        }
+      }
+      break;
+  
+    case 'c': 
+      if( nBuf>4 && 0==memcmp("enci", &aBuf[nBuf-4], 4) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-4) ){
+          memcpy(&aBuf[nBuf-4], "ence", 4);
+          *pnBuf = nBuf - 4 + 4;
+        }
+      }else if( nBuf>4 && 0==memcmp("anci", &aBuf[nBuf-4], 4) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-4) ){
+          memcpy(&aBuf[nBuf-4], "ance", 4);
+          *pnBuf = nBuf - 4 + 4;
+        }
+      }
+      break;
+  
+    case 'e': 
+      if( nBuf>4 && 0==memcmp("izer", &aBuf[nBuf-4], 4) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-4) ){
+          memcpy(&aBuf[nBuf-4], "ize", 3);
+          *pnBuf = nBuf - 4 + 3;
+        }
+      }
+      break;
+  
+    case 'g': 
+      if( nBuf>4 && 0==memcmp("logi", &aBuf[nBuf-4], 4) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-4) ){
+          memcpy(&aBuf[nBuf-4], "log", 3);
+          *pnBuf = nBuf - 4 + 3;
+        }
+      }
+      break;
+  
+    case 'l': 
+      if( nBuf>3 && 0==memcmp("bli", &aBuf[nBuf-3], 3) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-3) ){
+          memcpy(&aBuf[nBuf-3], "ble", 3);
+          *pnBuf = nBuf - 3 + 3;
+        }
+      }else if( nBuf>4 && 0==memcmp("alli", &aBuf[nBuf-4], 4) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-4) ){
+          memcpy(&aBuf[nBuf-4], "al", 2);
+          *pnBuf = nBuf - 4 + 2;
+        }
+      }else if( nBuf>5 && 0==memcmp("entli", &aBuf[nBuf-5], 5) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-5) ){
+          memcpy(&aBuf[nBuf-5], "ent", 3);
+          *pnBuf = nBuf - 5 + 3;
+        }
+      }else if( nBuf>3 && 0==memcmp("eli", &aBuf[nBuf-3], 3) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-3) ){
+          memcpy(&aBuf[nBuf-3], "e", 1);
+          *pnBuf = nBuf - 3 + 1;
+        }
+      }else if( nBuf>5 && 0==memcmp("ousli", &aBuf[nBuf-5], 5) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-5) ){
+          memcpy(&aBuf[nBuf-5], "ous", 3);
+          *pnBuf = nBuf - 5 + 3;
+        }
+      }
+      break;
+  
+    case 'o': 
+      if( nBuf>7 && 0==memcmp("ization", &aBuf[nBuf-7], 7) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-7) ){
+          memcpy(&aBuf[nBuf-7], "ize", 3);
+          *pnBuf = nBuf - 7 + 3;
+        }
+      }else if( nBuf>5 && 0==memcmp("ation", &aBuf[nBuf-5], 5) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-5) ){
+          memcpy(&aBuf[nBuf-5], "ate", 3);
+          *pnBuf = nBuf - 5 + 3;
+        }
+      }else if( nBuf>4 && 0==memcmp("ator", &aBuf[nBuf-4], 4) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-4) ){
+          memcpy(&aBuf[nBuf-4], "ate", 3);
+          *pnBuf = nBuf - 4 + 3;
+        }
+      }
+      break;
+  
+    case 's': 
+      if( nBuf>5 && 0==memcmp("alism", &aBuf[nBuf-5], 5) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-5) ){
+          memcpy(&aBuf[nBuf-5], "al", 2);
+          *pnBuf = nBuf - 5 + 2;
+        }
+      }else if( nBuf>7 && 0==memcmp("iveness", &aBuf[nBuf-7], 7) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-7) ){
+          memcpy(&aBuf[nBuf-7], "ive", 3);
+          *pnBuf = nBuf - 7 + 3;
+        }
+      }else if( nBuf>7 && 0==memcmp("fulness", &aBuf[nBuf-7], 7) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-7) ){
+          memcpy(&aBuf[nBuf-7], "ful", 3);
+          *pnBuf = nBuf - 7 + 3;
+        }
+      }else if( nBuf>7 && 0==memcmp("ousness", &aBuf[nBuf-7], 7) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-7) ){
+          memcpy(&aBuf[nBuf-7], "ous", 3);
+          *pnBuf = nBuf - 7 + 3;
+        }
+      }
+      break;
+  
+    case 't': 
+      if( nBuf>5 && 0==memcmp("aliti", &aBuf[nBuf-5], 5) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-5) ){
+          memcpy(&aBuf[nBuf-5], "al", 2);
+          *pnBuf = nBuf - 5 + 2;
+        }
+      }else if( nBuf>5 && 0==memcmp("iviti", &aBuf[nBuf-5], 5) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-5) ){
+          memcpy(&aBuf[nBuf-5], "ive", 3);
+          *pnBuf = nBuf - 5 + 3;
+        }
+      }else if( nBuf>6 && 0==memcmp("biliti", &aBuf[nBuf-6], 6) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-6) ){
+          memcpy(&aBuf[nBuf-6], "ble", 3);
+          *pnBuf = nBuf - 6 + 3;
+        }
+      }
+      break;
+  
+  }
+  return ret;
+}
+  
+
+static int fts5PorterStep3(char *aBuf, int *pnBuf){
+  int ret = 0;
+  int nBuf = *pnBuf;
+  switch( aBuf[nBuf-2] ){
+    
+    case 'a': 
+      if( nBuf>4 && 0==memcmp("ical", &aBuf[nBuf-4], 4) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-4) ){
+          memcpy(&aBuf[nBuf-4], "ic", 2);
+          *pnBuf = nBuf - 4 + 2;
+        }
+      }
+      break;
+  
+    case 's': 
+      if( nBuf>4 && 0==memcmp("ness", &aBuf[nBuf-4], 4) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-4) ){
+          *pnBuf = nBuf - 4;
+        }
+      }
+      break;
+  
+    case 't': 
+      if( nBuf>5 && 0==memcmp("icate", &aBuf[nBuf-5], 5) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-5) ){
+          memcpy(&aBuf[nBuf-5], "ic", 2);
+          *pnBuf = nBuf - 5 + 2;
+        }
+      }else if( nBuf>5 && 0==memcmp("iciti", &aBuf[nBuf-5], 5) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-5) ){
+          memcpy(&aBuf[nBuf-5], "ic", 2);
+          *pnBuf = nBuf - 5 + 2;
+        }
+      }
+      break;
+  
+    case 'u': 
+      if( nBuf>3 && 0==memcmp("ful", &aBuf[nBuf-3], 3) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-3) ){
+          *pnBuf = nBuf - 3;
+        }
+      }
+      break;
+  
+    case 'v': 
+      if( nBuf>5 && 0==memcmp("ative", &aBuf[nBuf-5], 5) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-5) ){
+          *pnBuf = nBuf - 5;
+        }
+      }
+      break;
+  
+    case 'z': 
+      if( nBuf>5 && 0==memcmp("alize", &aBuf[nBuf-5], 5) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-5) ){
+          memcpy(&aBuf[nBuf-5], "al", 2);
+          *pnBuf = nBuf - 5 + 2;
+        }
+      }
+      break;
+  
+  }
+  return ret;
+}
+  
+
+static int fts5PorterStep1B(char *aBuf, int *pnBuf){
+  int ret = 0;
+  int nBuf = *pnBuf;
+  switch( aBuf[nBuf-2] ){
+    
+    case 'e': 
+      if( nBuf>3 && 0==memcmp("eed", &aBuf[nBuf-3], 3) ){
+        if( fts5Porter_MGt0(aBuf, nBuf-3) ){
+          memcpy(&aBuf[nBuf-3], "ee", 2);
+          *pnBuf = nBuf - 3 + 2;
+        }
+      }else if( nBuf>2 && 0==memcmp("ed", &aBuf[nBuf-2], 2) ){
+        if( fts5Porter_Vowel(aBuf, nBuf-2) ){
+          *pnBuf = nBuf - 2;
+          ret = 1;
+        }
+      }
+      break;
+  
+    case 'n': 
+      if( nBuf>3 && 0==memcmp("ing", &aBuf[nBuf-3], 3) ){
+        if( fts5Porter_Vowel(aBuf, nBuf-3) ){
+          *pnBuf = nBuf - 3;
+          ret = 1;
+        }
+      }
+      break;
+  
+  }
+  return ret;
+}
+  
+/* 
+** GENERATED CODE ENDS HERE (mkportersteps.tcl)
+***************************************************************************
+**************************************************************************/
+
+static void fts5PorterStep1A(char *aBuf, int *pnBuf){
+  int nBuf = *pnBuf;
+  if( aBuf[nBuf-1]=='s' ){
+    if( aBuf[nBuf-2]=='e' ){
+      if( (nBuf>4 && aBuf[nBuf-4]=='s' && aBuf[nBuf-3]=='s') 
+       || (nBuf>3 && aBuf[nBuf-3]=='i' )
+      ){
+        *pnBuf = nBuf-2;
+      }else{
+        *pnBuf = nBuf-1;
+      }
+    }
+    else if( aBuf[nBuf-2]!='s' ){
+      *pnBuf = nBuf-1;
+    }
+  }
+}
+
+static int fts5PorterCb(
+  void *pCtx, 
+  int tflags,
+  const char *pToken, 
+  int nToken, 
+  int iStart, 
+  int iEnd
+){
+  PorterContext *p = (PorterContext*)pCtx;
+
+  char *aBuf;
+  int nBuf;
+
+  if( nToken>FTS5_PORTER_MAX_TOKEN || nToken<3 ) goto pass_through;
+  aBuf = p->aBuf;
+  nBuf = nToken;
+  memcpy(aBuf, pToken, nBuf);
+
+  /* Step 1. */
+  fts5PorterStep1A(aBuf, &nBuf);
+  if( fts5PorterStep1B(aBuf, &nBuf) ){
+    if( fts5PorterStep1B2(aBuf, &nBuf)==0 ){
+      char c = aBuf[nBuf-1];
+      if( fts5PorterIsVowel(c, 0)==0 
+       && c!='l' && c!='s' && c!='z' && c==aBuf[nBuf-2] 
+      ){
+        nBuf--;
+      }else if( fts5Porter_MEq1(aBuf, nBuf) && fts5Porter_Ostar(aBuf, nBuf) ){
+        aBuf[nBuf++] = 'e';
+      }
+    }
+  }
+
+  /* Step 1C. */
+  if( aBuf[nBuf-1]=='y' && fts5Porter_Vowel(aBuf, nBuf-1) ){
+    aBuf[nBuf-1] = 'i';
+  }
+
+  /* Steps 2 through 4. */
+  fts5PorterStep2(aBuf, &nBuf);
+  fts5PorterStep3(aBuf, &nBuf);
+  fts5PorterStep4(aBuf, &nBuf);
+
+  /* Step 5a. */
+  assert( nBuf>0 );
+  if( aBuf[nBuf-1]=='e' ){
+    if( fts5Porter_MGt1(aBuf, nBuf-1) 
+     || (fts5Porter_MEq1(aBuf, nBuf-1) && !fts5Porter_Ostar(aBuf, nBuf-1))
+    ){
+      nBuf--;
+    }
+  }
+
+  /* Step 5b. */
+  if( nBuf>1 && aBuf[nBuf-1]=='l' 
+   && aBuf[nBuf-2]=='l' && fts5Porter_MGt1(aBuf, nBuf-1) 
+  ){
+    nBuf--;
+  }
+
+  return p->xToken(p->pCtx, tflags, aBuf, nBuf, iStart, iEnd);
+
+ pass_through:
+  return p->xToken(p->pCtx, tflags, pToken, nToken, iStart, iEnd);
+}
+
+/*
+** Tokenize using the porter tokenizer.
+*/
+static int fts5PorterTokenize(
+  Fts5Tokenizer *pTokenizer,
+  void *pCtx,
+  int flags,
+  const char *pText, int nText,
+  int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd)
+){
+  PorterTokenizer *p = (PorterTokenizer*)pTokenizer;
+  PorterContext sCtx;
+  sCtx.xToken = xToken;
+  sCtx.pCtx = pCtx;
+  sCtx.aBuf = p->aBuf;
+  return p->tokenizer.xTokenize(
+      p->pTokenizer, (void*)&sCtx, flags, pText, nText, fts5PorterCb
+  );
+}
+
+/*
+** Register all built-in tokenizers with FTS5.
+*/
+static int sqlite3Fts5TokenizerInit(fts5_api *pApi){
+  struct BuiltinTokenizer {
+    const char *zName;
+    fts5_tokenizer x;
+  } aBuiltin[] = {
+    { "unicode61", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}},
+    { "ascii",     {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }},
+    { "porter",    {fts5PorterCreate, fts5PorterDelete, fts5PorterTokenize }},
+  };
+  
+  int rc = SQLITE_OK;             /* Return code */
+  int i;                          /* To iterate through builtin functions */
+
+  for(i=0; rc==SQLITE_OK && i<sizeof(aBuiltin)/sizeof(aBuiltin[0]); i++){
+    rc = pApi->xCreateTokenizer(pApi,
+        aBuiltin[i].zName,
+        (void*)pApi,
+        &aBuiltin[i].x,
+        0
+    );
+  }
+
+  return rc;
+}
+
+
+
+/*
+** 2012 May 25
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+******************************************************************************
+*/
+
+/*
+** DO NOT EDIT THIS MACHINE GENERATED FILE.
+*/
+
+
+/* #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( c<128 ){
+    return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
+  }else if( 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;
+}
+
+
+/*
+** If the argument is a codepoint corresponding to a lowercase letter
+** in the ASCII range with a diacritic added, return the codepoint
+** of the ASCII letter only. For example, if passed 235 - "LATIN
+** SMALL LETTER E WITH DIAERESIS" - return 65 ("LATIN SMALL LETTER
+** E"). The resuls of passing a codepoint that corresponds to an
+** uppercase letter are undefined.
+*/
+static int fts5_remove_diacritic(int c){
+  unsigned short aDia[] = {
+        0,  1797,  1848,  1859,  1891,  1928,  1940,  1995, 
+     2024,  2040,  2060,  2110,  2168,  2206,  2264,  2286, 
+     2344,  2383,  2472,  2488,  2516,  2596,  2668,  2732, 
+     2782,  2842,  2894,  2954,  2984,  3000,  3028,  3336, 
+     3456,  3696,  3712,  3728,  3744,  3896,  3912,  3928, 
+     3968,  4008,  4040,  4106,  4138,  4170,  4202,  4234, 
+     4266,  4296,  4312,  4344,  4408,  4424,  4472,  4504, 
+     6148,  6198,  6264,  6280,  6360,  6429,  6505,  6529, 
+    61448, 61468, 61534, 61592, 61642, 61688, 61704, 61726, 
+    61784, 61800, 61836, 61880, 61914, 61948, 61998, 62122, 
+    62154, 62200, 62218, 62302, 62364, 62442, 62478, 62536, 
+    62554, 62584, 62604, 62640, 62648, 62656, 62664, 62730, 
+    62924, 63050, 63082, 63274, 63390, 
+  };
+  char aChar[] = {
+    '\0', 'a',  'c',  'e',  'i',  'n',  'o',  'u',  'y',  'y',  'a',  'c',  
+    'd',  'e',  'e',  'g',  'h',  'i',  'j',  'k',  'l',  'n',  'o',  'r',  
+    's',  't',  'u',  'u',  'w',  'y',  'z',  'o',  'u',  'a',  'i',  'o',  
+    'u',  'g',  'k',  'o',  'j',  'g',  'n',  'a',  'e',  'i',  'o',  'r',  
+    'u',  's',  't',  'h',  'a',  'e',  'o',  'y',  '\0', '\0', '\0', '\0', 
+    '\0', '\0', '\0', '\0', 'a',  'b',  'd',  'd',  'e',  'f',  'g',  'h',  
+    'h',  'i',  'k',  'l',  'l',  'm',  'n',  'p',  'r',  'r',  's',  't',  
+    'u',  'v',  'w',  'w',  'x',  'y',  'z',  'h',  't',  'w',  'y',  'a',  
+    'e',  'i',  'o',  'u',  'y',  
+  };
+
+  unsigned int key = (((unsigned int)c)<<3) | 0x00000007;
+  int iRes = 0;
+  int iHi = sizeof(aDia)/sizeof(aDia[0]) - 1;
+  int iLo = 0;
+  while( iHi>=iLo ){
+    int iTest = (iHi + iLo) / 2;
+    if( key >= aDia[iTest] ){
+      iRes = iTest;
+      iLo = iTest+1;
+    }else{
+      iHi = iTest-1;
+    }
+  }
+  assert( key>=aDia[iRes] );
+  return ((c > (aDia[iRes]>>3) + (aDia[iRes]&0x07)) ? c : (int)aChar[iRes]);
+}
+
+
+/*
+** Return true if the argument interpreted as a unicode codepoint
+** is a diacritical modifier character.
+*/
+static int sqlite3Fts5UnicodeIsdiacritic(int c){
+  unsigned int mask0 = 0x08029FDF;
+  unsigned int mask1 = 0x000361F8;
+  if( c<768 || c>817 ) return 0;
+  return (c < 768+32) ?
+      (mask0 & (1 << (c-768))) :
+      (mask1 & (1 << (c-768-32)));
+}
+
+
+/*
+** Interpret the argument as a unicode codepoint. If the codepoint
+** is an upper case character that has a lower case equivalent,
+** return the codepoint corresponding to the lower case version.
+** Otherwise, return a copy of the argument.
+**
+** The results are undefined if the value passed to this function
+** is less than zero.
+*/
+static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){
+  /* Each entry in the following array defines a rule for folding a range
+  ** of codepoints to lower case. The rule applies to a range of nRange
+  ** codepoints starting at codepoint iCode.
+  **
+  ** If the least significant bit in flags is clear, then the rule applies
+  ** to all nRange codepoints (i.e. all nRange codepoints are upper case and
+  ** need to be folded). Or, if it is set, then the rule only applies to
+  ** every second codepoint in the range, starting with codepoint C.
+  **
+  ** The 7 most significant bits in flags are an index into the aiOff[]
+  ** array. If a specific codepoint C does require folding, then its lower
+  ** case equivalent is ((C + aiOff[flags>>1]) & 0xFFFF).
+  **
+  ** The contents of this array are generated by parsing the CaseFolding.txt
+  ** file distributed as part of the "Unicode Character Database". See
+  ** http://www.unicode.org for details.
+  */
+  static const struct TableEntry {
+    unsigned short iCode;
+    unsigned char flags;
+    unsigned char nRange;
+  } aEntry[] = {
+    {65, 14, 26},          {181, 64, 1},          {192, 14, 23},
+    {216, 14, 7},          {256, 1, 48},          {306, 1, 6},
+    {313, 1, 16},          {330, 1, 46},          {376, 116, 1},
+    {377, 1, 6},           {383, 104, 1},         {385, 50, 1},
+    {386, 1, 4},           {390, 44, 1},          {391, 0, 1},
+    {393, 42, 2},          {395, 0, 1},           {398, 32, 1},
+    {399, 38, 1},          {400, 40, 1},          {401, 0, 1},
+    {403, 42, 1},          {404, 46, 1},          {406, 52, 1},
+    {407, 48, 1},          {408, 0, 1},           {412, 52, 1},
+    {413, 54, 1},          {415, 56, 1},          {416, 1, 6},
+    {422, 60, 1},          {423, 0, 1},           {425, 60, 1},
+    {428, 0, 1},           {430, 60, 1},          {431, 0, 1},
+    {433, 58, 2},          {435, 1, 4},           {439, 62, 1},
+    {440, 0, 1},           {444, 0, 1},           {452, 2, 1},
+    {453, 0, 1},           {455, 2, 1},           {456, 0, 1},
+    {458, 2, 1},           {459, 1, 18},          {478, 1, 18},
+    {497, 2, 1},           {498, 1, 4},           {502, 122, 1},
+    {503, 134, 1},         {504, 1, 40},          {544, 110, 1},
+    {546, 1, 18},          {570, 70, 1},          {571, 0, 1},
+    {573, 108, 1},         {574, 68, 1},          {577, 0, 1},
+    {579, 106, 1},         {580, 28, 1},          {581, 30, 1},
+    {582, 1, 10},          {837, 36, 1},          {880, 1, 4},
+    {886, 0, 1},           {902, 18, 1},          {904, 16, 3},
+    {908, 26, 1},          {910, 24, 2},          {913, 14, 17},
+    {931, 14, 9},          {962, 0, 1},           {975, 4, 1},
+    {976, 140, 1},         {977, 142, 1},         {981, 146, 1},
+    {982, 144, 1},         {984, 1, 24},          {1008, 136, 1},
+    {1009, 138, 1},        {1012, 130, 1},        {1013, 128, 1},
+    {1015, 0, 1},          {1017, 152, 1},        {1018, 0, 1},
+    {1021, 110, 3},        {1024, 34, 16},        {1040, 14, 32},
+    {1120, 1, 34},         {1162, 1, 54},         {1216, 6, 1},
+    {1217, 1, 14},         {1232, 1, 88},         {1329, 22, 38},
+    {4256, 66, 38},        {4295, 66, 1},         {4301, 66, 1},
+    {7680, 1, 150},        {7835, 132, 1},        {7838, 96, 1},
+    {7840, 1, 96},         {7944, 150, 8},        {7960, 150, 6},
+    {7976, 150, 8},        {7992, 150, 8},        {8008, 150, 6},
+    {8025, 151, 8},        {8040, 150, 8},        {8072, 150, 8},
+    {8088, 150, 8},        {8104, 150, 8},        {8120, 150, 2},
+    {8122, 126, 2},        {8124, 148, 1},        {8126, 100, 1},
+    {8136, 124, 4},        {8140, 148, 1},        {8152, 150, 2},
+    {8154, 120, 2},        {8168, 150, 2},        {8170, 118, 2},
+    {8172, 152, 1},        {8184, 112, 2},        {8186, 114, 2},
+    {8188, 148, 1},        {8486, 98, 1},         {8490, 92, 1},
+    {8491, 94, 1},         {8498, 12, 1},         {8544, 8, 16},
+    {8579, 0, 1},          {9398, 10, 26},        {11264, 22, 47},
+    {11360, 0, 1},         {11362, 88, 1},        {11363, 102, 1},
+    {11364, 90, 1},        {11367, 1, 6},         {11373, 84, 1},
+    {11374, 86, 1},        {11375, 80, 1},        {11376, 82, 1},
+    {11378, 0, 1},         {11381, 0, 1},         {11390, 78, 2},
+    {11392, 1, 100},       {11499, 1, 4},         {11506, 0, 1},
+    {42560, 1, 46},        {42624, 1, 24},        {42786, 1, 14},
+    {42802, 1, 62},        {42873, 1, 4},         {42877, 76, 1},
+    {42878, 1, 10},        {42891, 0, 1},         {42893, 74, 1},
+    {42896, 1, 4},         {42912, 1, 10},        {42922, 72, 1},
+    {65313, 14, 26},       
+  };
+  static const unsigned short aiOff[] = {
+   1,     2,     8,     15,    16,    26,    28,    32,    
+   37,    38,    40,    48,    63,    64,    69,    71,    
+   79,    80,    116,   202,   203,   205,   206,   207,   
+   209,   210,   211,   213,   214,   217,   218,   219,   
+   775,   7264,  10792, 10795, 23228, 23256, 30204, 54721, 
+   54753, 54754, 54756, 54787, 54793, 54809, 57153, 57274, 
+   57921, 58019, 58363, 61722, 65268, 65341, 65373, 65406, 
+   65408, 65410, 65415, 65424, 65436, 65439, 65450, 65462, 
+   65472, 65476, 65478, 65480, 65482, 65488, 65506, 65511, 
+   65514, 65521, 65527, 65528, 65529, 
+  };
+
+  int ret = c;
+
+  assert( sizeof(unsigned short)==2 && sizeof(unsigned char)==1 );
+
+  if( c<128 ){
+    if( c>='A' && c<='Z' ) ret = c + ('a' - 'A');
+  }else if( c<65536 ){
+    const struct TableEntry *p;
+    int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
+    int iLo = 0;
+    int iRes = -1;
+
+    assert( c>aEntry[0].iCode );
+    while( iHi>=iLo ){
+      int iTest = (iHi + iLo) / 2;
+      int cmp = (c - aEntry[iTest].iCode);
+      if( cmp>=0 ){
+        iRes = iTest;
+        iLo = iTest+1;
+      }else{
+        iHi = iTest-1;
+      }
+    }
+
+    assert( iRes>=0 && c>=aEntry[iRes].iCode );
+    p = &aEntry[iRes];
+    if( c<(p->iCode + p->nRange) && 0==(0x01 & p->flags & (p->iCode ^ c)) ){
+      ret = (c + (aiOff[p->flags>>1])) & 0x0000FFFF;
+      assert( ret>0 );
+    }
+
+    if( bRemoveDiacritic ) ret = fts5_remove_diacritic(ret);
+  }
+  
+  else if( c>=66560 && c<66600 ){
+    ret = c + 40;
+  }
+
+  return ret;
+}
+
+/*
+** 2015 May 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.
+**
+******************************************************************************
+**
+** Routines for varint serialization and deserialization.
+*/
+
+
+
+/*
+** This is a copy of the sqlite3GetVarint32() routine from the SQLite core.
+** Except, this version does handle the single byte case that the core
+** version depends on being handled before its function is called.
+*/
+static int sqlite3Fts5GetVarint32(const unsigned char *p, u32 *v){
+  u32 a,b;
+
+  /* The 1-byte case. Overwhelmingly the most common. */
+  a = *p;
+  /* a: p0 (unmasked) */
+  if (!(a&0x80))
+  {
+    /* Values between 0 and 127 */
+    *v = a;
+    return 1;
+  }
+
+  /* The 2-byte case */
+  p++;
+  b = *p;
+  /* b: p1 (unmasked) */
+  if (!(b&0x80))
+  {
+    /* Values between 128 and 16383 */
+    a &= 0x7f;
+    a = a<<7;
+    *v = a | b;
+    return 2;
+  }
+
+  /* The 3-byte case */
+  p++;
+  a = a<<14;
+  a |= *p;
+  /* a: p0<<14 | p2 (unmasked) */
+  if (!(a&0x80))
+  {
+    /* Values between 16384 and 2097151 */
+    a &= (0x7f<<14)|(0x7f);
+    b &= 0x7f;
+    b = b<<7;
+    *v = a | b;
+    return 3;
+  }
+
+  /* A 32-bit varint is used to store size information in btrees.
+  ** Objects are rarely larger than 2MiB limit of a 3-byte varint.
+  ** A 3-byte varint is sufficient, for example, to record the size
+  ** of a 1048569-byte BLOB or string.
+  **
+  ** We only unroll the first 1-, 2-, and 3- byte cases.  The very
+  ** rare larger cases can be handled by the slower 64-bit varint
+  ** routine.
+  */
+  {
+    u64 v64;
+    u8 n;
+    p -= 2;
+    n = sqlite3Fts5GetVarint(p, &v64);
+    *v = (u32)v64;
+    assert( n>3 && n<=9 );
+    return n;
+  }
+}
+
+
+/*
+** Bitmasks used by sqlite3GetVarint().  These precomputed constants
+** are defined here rather than simply putting the constant expressions
+** inline in order to work around bugs in the RVT compiler.
+**
+** SLOT_2_0     A mask for  (0x7f<<14) | 0x7f
+**
+** SLOT_4_2_0   A mask for  (0x7f<<28) | SLOT_2_0
+*/
+#define SLOT_2_0     0x001fc07f
+#define SLOT_4_2_0   0xf01fc07f
+
+/*
+** Read a 64-bit variable-length integer from memory starting at p[0].
+** Return the number of bytes read.  The value is stored in *v.
+*/
+static u8 sqlite3Fts5GetVarint(const unsigned char *p, u64 *v){
+  u32 a,b,s;
+
+  a = *p;
+  /* a: p0 (unmasked) */
+  if (!(a&0x80))
+  {
+    *v = a;
+    return 1;
+  }
+
+  p++;
+  b = *p;
+  /* b: p1 (unmasked) */
+  if (!(b&0x80))
+  {
+    a &= 0x7f;
+    a = a<<7;
+    a |= b;
+    *v = a;
+    return 2;
+  }
+
+  /* Verify that constants are precomputed correctly */
+  assert( SLOT_2_0 == ((0x7f<<14) | (0x7f)) );
+  assert( SLOT_4_2_0 == ((0xfU<<28) | (0x7f<<14) | (0x7f)) );
+
+  p++;
+  a = a<<14;
+  a |= *p;
+  /* a: p0<<14 | p2 (unmasked) */
+  if (!(a&0x80))
+  {
+    a &= SLOT_2_0;
+    b &= 0x7f;
+    b = b<<7;
+    a |= b;
+    *v = a;
+    return 3;
+  }
+
+  /* CSE1 from below */
+  a &= SLOT_2_0;
+  p++;
+  b = b<<14;
+  b |= *p;
+  /* b: p1<<14 | p3 (unmasked) */
+  if (!(b&0x80))
+  {
+    b &= SLOT_2_0;
+    /* moved CSE1 up */
+    /* a &= (0x7f<<14)|(0x7f); */
+    a = a<<7;
+    a |= b;
+    *v = a;
+    return 4;
+  }
+
+  /* a: p0<<14 | p2 (masked) */
+  /* b: p1<<14 | p3 (unmasked) */
+  /* 1:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */
+  /* moved CSE1 up */
+  /* a &= (0x7f<<14)|(0x7f); */
+  b &= SLOT_2_0;
+  s = a;
+  /* s: p0<<14 | p2 (masked) */
+
+  p++;
+  a = a<<14;
+  a |= *p;
+  /* a: p0<<28 | p2<<14 | p4 (unmasked) */
+  if (!(a&0x80))
+  {
+    /* we can skip these cause they were (effectively) done above in calc'ing s */
+    /* a &= (0x7f<<28)|(0x7f<<14)|(0x7f); */
+    /* b &= (0x7f<<14)|(0x7f); */
+    b = b<<7;
+    a |= b;
+    s = s>>18;
+    *v = ((u64)s)<<32 | a;
+    return 5;
+  }
+
+  /* 2:save off p0<<21 | p1<<14 | p2<<7 | p3 (masked) */
+  s = s<<7;
+  s |= b;
+  /* s: p0<<21 | p1<<14 | p2<<7 | p3 (masked) */
+
+  p++;
+  b = b<<14;
+  b |= *p;
+  /* b: p1<<28 | p3<<14 | p5 (unmasked) */
+  if (!(b&0x80))
+  {
+    /* we can skip this cause it was (effectively) done above in calc'ing s */
+    /* b &= (0x7f<<28)|(0x7f<<14)|(0x7f); */
+    a &= SLOT_2_0;
+    a = a<<7;
+    a |= b;
+    s = s>>18;
+    *v = ((u64)s)<<32 | a;
+    return 6;
+  }
+
+  p++;
+  a = a<<14;
+  a |= *p;
+  /* a: p2<<28 | p4<<14 | p6 (unmasked) */
+  if (!(a&0x80))
+  {
+    a &= SLOT_4_2_0;
+    b &= SLOT_2_0;
+    b = b<<7;
+    a |= b;
+    s = s>>11;
+    *v = ((u64)s)<<32 | a;
+    return 7;
+  }
+
+  /* CSE2 from below */
+  a &= SLOT_2_0;
+  p++;
+  b = b<<14;
+  b |= *p;
+  /* b: p3<<28 | p5<<14 | p7 (unmasked) */
+  if (!(b&0x80))
+  {
+    b &= SLOT_4_2_0;
+    /* moved CSE2 up */
+    /* a &= (0x7f<<14)|(0x7f); */
+    a = a<<7;
+    a |= b;
+    s = s>>4;
+    *v = ((u64)s)<<32 | a;
+    return 8;
+  }
+
+  p++;
+  a = a<<15;
+  a |= *p;
+  /* a: p4<<29 | p6<<15 | p8 (unmasked) */
+
+  /* moved CSE2 up */
+  /* a &= (0x7f<<29)|(0x7f<<15)|(0xff); */
+  b &= SLOT_2_0;
+  b = b<<8;
+  a |= b;
+
+  s = s<<4;
+  b = p[-4];
+  b &= 0x7f;
+  b = b>>3;
+  s |= b;
+
+  *v = ((u64)s)<<32 | a;
+
+  return 9;
+}
+
+/*
+** The variable-length integer encoding is as follows:
+**
+** KEY:
+**         A = 0xxxxxxx    7 bits of data and one flag bit
+**         B = 1xxxxxxx    7 bits of data and one flag bit
+**         C = xxxxxxxx    8 bits of data
+**
+**  7 bits - A
+** 14 bits - BA
+** 21 bits - BBA
+** 28 bits - BBBA
+** 35 bits - BBBBA
+** 42 bits - BBBBBA
+** 49 bits - BBBBBBA
+** 56 bits - BBBBBBBA
+** 64 bits - BBBBBBBBC
+*/
+
+#ifdef SQLITE_NOINLINE
+# define FTS5_NOINLINE SQLITE_NOINLINE
+#else
+# define FTS5_NOINLINE
+#endif
+
+/*
+** Write a 64-bit variable-length integer to memory starting at p[0].
+** The length of data write will be between 1 and 9 bytes.  The number
+** of bytes written is returned.
+**
+** A variable-length integer consists of the lower 7 bits of each byte
+** for all bytes that have the 8th bit set and one byte with the 8th
+** bit clear.  Except, if we get to the 9th byte, it stores the full
+** 8 bits and is the last byte.
+*/
+static int FTS5_NOINLINE fts5PutVarint64(unsigned char *p, u64 v){
+  int i, j, n;
+  u8 buf[10];
+  if( v & (((u64)0xff000000)<<32) ){
+    p[8] = (u8)v;
+    v >>= 8;
+    for(i=7; i>=0; i--){
+      p[i] = (u8)((v & 0x7f) | 0x80);
+      v >>= 7;
+    }
+    return 9;
+  }    
+  n = 0;
+  do{
+    buf[n++] = (u8)((v & 0x7f) | 0x80);
+    v >>= 7;
+  }while( v!=0 );
+  buf[0] &= 0x7f;
+  assert( n<=9 );
+  for(i=0, j=n-1; j>=0; j--, i++){
+    p[i] = buf[j];
+  }
+  return n;
+}
+
+static int sqlite3Fts5PutVarint(unsigned char *p, u64 v){
+  if( v<=0x7f ){
+    p[0] = v&0x7f;
+    return 1;
+  }
+  if( v<=0x3fff ){
+    p[0] = ((v>>7)&0x7f)|0x80;
+    p[1] = v&0x7f;
+    return 2;
+  }
+  return fts5PutVarint64(p,v);
+}
+
+
+static int sqlite3Fts5GetVarintLen(u32 iVal){
+  if( iVal<(1 << 7 ) ) return 1;
+  if( iVal<(1 << 14) ) return 2;
+  if( iVal<(1 << 21) ) return 3;
+  if( iVal<(1 << 28) ) return 4;
+  return 5;
+}
+
+
+/*
+** 2015 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.
+**
+******************************************************************************
+**
+** This is an SQLite virtual table module implementing direct access to an
+** existing FTS5 index. The module may create several different types of 
+** tables:
+**
+** col:
+**     CREATE TABLE vocab(term, col, doc, cnt, PRIMARY KEY(term, col));
+**
+**   One row for each term/column combination. The value of $doc is set to
+**   the number of fts5 rows that contain at least one instance of term
+**   $term within column $col. Field $cnt is set to the total number of 
+**   instances of term $term in column $col (in any row of the fts5 table). 
+**
+** row:
+**     CREATE TABLE vocab(term, doc, cnt, PRIMARY KEY(term));
+**
+**   One row for each term in the database. The value of $doc is set to
+**   the number of fts5 rows that contain at least one instance of term
+**   $term. Field $cnt is set to the total number of instances of term 
+**   $term in the database.
+*/
+
+
+
+
+typedef struct Fts5VocabTable Fts5VocabTable;
+typedef struct Fts5VocabCursor Fts5VocabCursor;
+
+struct Fts5VocabTable {
+  sqlite3_vtab base;
+  char *zFts5Tbl;                 /* Name of fts5 table */
+  char *zFts5Db;                  /* Db containing fts5 table */
+  sqlite3 *db;                    /* Database handle */
+  Fts5Global *pGlobal;            /* FTS5 global object for this database */
+  int eType;                      /* FTS5_VOCAB_COL or ROW */
+};
+
+struct Fts5VocabCursor {
+  sqlite3_vtab_cursor base;
+  sqlite3_stmt *pStmt;            /* Statement holding lock on pIndex */
+  Fts5Index *pIndex;              /* Associated FTS5 index */
+
+  int bEof;                       /* True if this cursor is at EOF */
+  Fts5IndexIter *pIter;           /* Term/rowid iterator object */
+
+  /* These are used by 'col' tables only */
+  int nCol;
+  int iCol;
+  i64 *aCnt;
+  i64 *aDoc;
+
+  /* Output values */
+  i64 rowid;                      /* This table's current rowid value */
+  Fts5Buffer term;                /* Current value of 'term' column */
+  i64 aVal[3];                    /* Up to three columns left of 'term' */
+};
+
+#define FTS5_VOCAB_COL    0
+#define FTS5_VOCAB_ROW    1
+
+#define FTS5_VOCAB_COL_SCHEMA  "term, col, doc, cnt"
+#define FTS5_VOCAB_ROW_SCHEMA  "term, doc, cnt"
+
+/*
+** Translate a string containing an fts5vocab table type to an 
+** FTS5_VOCAB_XXX constant. If successful, set *peType to the output
+** value and return SQLITE_OK. Otherwise, set *pzErr to an error message
+** and return SQLITE_ERROR.
+*/
+static int fts5VocabTableType(const char *zType, char **pzErr, int *peType){
+  int rc = SQLITE_OK;
+  char *zCopy = sqlite3Fts5Strndup(&rc, zType, -1);
+  if( rc==SQLITE_OK ){
+    sqlite3Fts5Dequote(zCopy);
+    if( sqlite3_stricmp(zCopy, "col")==0 ){
+      *peType = FTS5_VOCAB_COL;
+    }else
+
+    if( sqlite3_stricmp(zCopy, "row")==0 ){
+      *peType = FTS5_VOCAB_ROW;
+    }else
+    {
+      *pzErr = sqlite3_mprintf("fts5vocab: unknown table type: %Q", zCopy);
+      rc = SQLITE_ERROR;
+    }
+    sqlite3_free(zCopy);
+  }
+
+  return rc;
+}
+
+
+/*
+** The xDisconnect() virtual table method.
+*/
+static int fts5VocabDisconnectMethod(sqlite3_vtab *pVtab){
+  Fts5VocabTable *pTab = (Fts5VocabTable*)pVtab;
+  sqlite3_free(pTab);
+  return SQLITE_OK;
+}
+
+/*
+** The xDestroy() virtual table method.
+*/
+static int fts5VocabDestroyMethod(sqlite3_vtab *pVtab){
+  Fts5VocabTable *pTab = (Fts5VocabTable*)pVtab;
+  sqlite3_free(pTab);
+  return SQLITE_OK;
+}
+
+/*
+** This function is the implementation of both the xConnect and xCreate
+** methods of the FTS3 virtual table.
+**
+** The argv[] array contains the following:
+**
+**   argv[0]   -> module name  ("fts5vocab")
+**   argv[1]   -> database name
+**   argv[2]   -> table name
+**
+** then:
+**
+**   argv[3]   -> name of fts5 table
+**   argv[4]   -> type of fts5vocab table
+**
+** or, for tables in the TEMP schema only.
+**
+**   argv[3]   -> name of fts5 tables database
+**   argv[4]   -> name of fts5 table
+**   argv[5]   -> type of fts5vocab table
+*/
+static int fts5VocabInitVtab(
+  sqlite3 *db,                    /* The SQLite database connection */
+  void *pAux,                     /* Pointer to Fts5Global object */
+  int argc,                       /* Number of elements in argv array */
+  const char * const *argv,       /* xCreate/xConnect argument array */
+  sqlite3_vtab **ppVTab,          /* Write the resulting vtab structure here */
+  char **pzErr                    /* Write any error message here */
+){
+  const char *azSchema[] = { 
+    "CREATE TABlE vocab(" FTS5_VOCAB_COL_SCHEMA  ")", 
+    "CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA  ")"
+  };
+
+  Fts5VocabTable *pRet = 0;
+  int rc = SQLITE_OK;             /* Return code */
+  int bDb;
+
+  bDb = (argc==6 && strlen(argv[1])==4 && memcmp("temp", argv[1], 4)==0);
+
+  if( argc!=5 && bDb==0 ){
+    *pzErr = sqlite3_mprintf("wrong number of vtable arguments");
+    rc = SQLITE_ERROR;
+  }else{
+    int nByte;                      /* Bytes of space to allocate */
+    const char *zDb = bDb ? argv[3] : argv[1];
+    const char *zTab = bDb ? argv[4] : argv[3];
+    const char *zType = bDb ? argv[5] : argv[4];
+    int nDb = strlen(zDb)+1; 
+    int nTab = strlen(zTab)+1;
+    int eType;
+    
+    rc = fts5VocabTableType(zType, pzErr, &eType);
+    if( rc==SQLITE_OK ){
+      assert( eType>=0 && eType<sizeof(azSchema)/sizeof(azSchema[0]) );
+      rc = sqlite3_declare_vtab(db, azSchema[eType]);
+    }
+
+    nByte = sizeof(Fts5VocabTable) + nDb + nTab;
+    pRet = sqlite3Fts5MallocZero(&rc, nByte);
+    if( pRet ){
+      pRet->pGlobal = (Fts5Global*)pAux;
+      pRet->eType = eType;
+      pRet->db = db;
+      pRet->zFts5Tbl = (char*)&pRet[1];
+      pRet->zFts5Db = &pRet->zFts5Tbl[nTab];
+      memcpy(pRet->zFts5Tbl, zTab, nTab);
+      memcpy(pRet->zFts5Db, zDb, nDb);
+      sqlite3Fts5Dequote(pRet->zFts5Tbl);
+      sqlite3Fts5Dequote(pRet->zFts5Db);
+    }
+  }
+
+  *ppVTab = (sqlite3_vtab*)pRet;
+  return rc;
+}
+
+
+/*
+** The xConnect() and xCreate() methods for the virtual table. All the
+** work is done in function fts5VocabInitVtab().
+*/
+static int fts5VocabConnectMethod(
+  sqlite3 *db,                    /* Database connection */
+  void *pAux,                     /* Pointer to tokenizer hash table */
+  int argc,                       /* Number of elements in argv array */
+  const char * const *argv,       /* xCreate/xConnect argument array */
+  sqlite3_vtab **ppVtab,          /* OUT: New sqlite3_vtab object */
+  char **pzErr                    /* OUT: sqlite3_malloc'd error message */
+){
+  return fts5VocabInitVtab(db, pAux, argc, argv, ppVtab, pzErr);
+}
+static int fts5VocabCreateMethod(
+  sqlite3 *db,                    /* Database connection */
+  void *pAux,                     /* Pointer to tokenizer hash table */
+  int argc,                       /* Number of elements in argv array */
+  const char * const *argv,       /* xCreate/xConnect argument array */
+  sqlite3_vtab **ppVtab,          /* OUT: New sqlite3_vtab object */
+  char **pzErr                    /* OUT: sqlite3_malloc'd error message */
+){
+  return fts5VocabInitVtab(db, pAux, argc, argv, ppVtab, pzErr);
+}
+
+/* 
+** Implementation of the xBestIndex method.
+*/
+static int fts5VocabBestIndexMethod(
+  sqlite3_vtab *pVTab, 
+  sqlite3_index_info *pInfo
+){
+  return SQLITE_OK;
+}
+
+/*
+** Implementation of xOpen method.
+*/
+static int fts5VocabOpenMethod(
+  sqlite3_vtab *pVTab, 
+  sqlite3_vtab_cursor **ppCsr
+){
+  Fts5VocabTable *pTab = (Fts5VocabTable*)pVTab;
+  Fts5Index *pIndex = 0;
+  int nCol = 0;
+  Fts5VocabCursor *pCsr = 0;
+  int rc = SQLITE_OK;
+  sqlite3_stmt *pStmt = 0;
+  char *zSql = 0;
+  int nByte;
+
+  zSql = sqlite3Fts5Mprintf(&rc,
+      "SELECT t.%Q FROM %Q.%Q AS t WHERE t.%Q MATCH '*id'",
+      pTab->zFts5Tbl, pTab->zFts5Db, pTab->zFts5Tbl, pTab->zFts5Tbl
+  );
+  if( zSql ){
+    rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pStmt, 0);
+  }
+  sqlite3_free(zSql);
+  assert( rc==SQLITE_OK || pStmt==0 );
+  if( rc==SQLITE_ERROR ) rc = SQLITE_OK;
+
+  if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
+    i64 iId = sqlite3_column_int64(pStmt, 0);
+    pIndex = sqlite3Fts5IndexFromCsrid(pTab->pGlobal, iId, &nCol);
+  }
+
+  if( rc==SQLITE_OK && pIndex==0 ){
+    rc = sqlite3_finalize(pStmt);
+    pStmt = 0;
+    if( rc==SQLITE_OK ){
+      pVTab->zErrMsg = sqlite3_mprintf(
+          "no such fts5 table: %s.%s", pTab->zFts5Db, pTab->zFts5Tbl
+      );
+      rc = SQLITE_ERROR;
+    }
+  }
+
+  nByte = nCol * sizeof(i64) * 2 + sizeof(Fts5VocabCursor);
+  pCsr = (Fts5VocabCursor*)sqlite3Fts5MallocZero(&rc, nByte);
+  if( pCsr ){
+    pCsr->pIndex = pIndex;
+    pCsr->pStmt = pStmt;
+    pCsr->nCol = nCol;
+    pCsr->aCnt = (i64*)&pCsr[1];
+    pCsr->aDoc = &pCsr->aCnt[nCol];
+  }else{
+    sqlite3_finalize(pStmt);
+  }
+
+  *ppCsr = (sqlite3_vtab_cursor*)pCsr;
+  return rc;
+}
+
+static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){
+  pCsr->rowid = 0;
+  sqlite3Fts5IterClose(pCsr->pIter);
+  pCsr->pIter = 0;
+}
+
+/*
+** Close the cursor.  For additional information see the documentation
+** on the xClose method of the virtual table interface.
+*/
+static int fts5VocabCloseMethod(sqlite3_vtab_cursor *pCursor){
+  Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
+  fts5VocabResetCursor(pCsr);
+  sqlite3Fts5BufferFree(&pCsr->term);
+  sqlite3_finalize(pCsr->pStmt);
+  sqlite3_free(pCsr);
+  return SQLITE_OK;
+}
+
+
+/*
+** Advance the cursor to the next row in the table.
+*/
+static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
+  Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
+  Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab;
+  int rc = SQLITE_OK;
+
+  pCsr->rowid++;
+
+  if( pTab->eType==FTS5_VOCAB_COL ){
+    for(pCsr->iCol++; pCsr->iCol<pCsr->nCol; pCsr->iCol++){
+      if( pCsr->aCnt[pCsr->iCol] ) break;
+    }
+  }
+
+  if( pTab->eType==FTS5_VOCAB_ROW || pCsr->iCol>=pCsr->nCol ){
+    if( sqlite3Fts5IterEof(pCsr->pIter) ){
+      pCsr->bEof = 1;
+    }else{
+      const char *zTerm;
+      int nTerm;
+
+      zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
+      sqlite3Fts5BufferSet(&rc, &pCsr->term, nTerm, (const u8*)zTerm);
+      memset(pCsr->aVal, 0, sizeof(pCsr->aVal));
+      memset(pCsr->aCnt, 0, pCsr->nCol * sizeof(i64));
+      memset(pCsr->aDoc, 0, pCsr->nCol * sizeof(i64));
+      pCsr->iCol = 0;
+
+      assert( pTab->eType==FTS5_VOCAB_COL || pTab->eType==FTS5_VOCAB_ROW );
+      while( rc==SQLITE_OK ){
+        i64 dummy;
+        const u8 *pPos; int nPos;   /* Position list */
+        i64 iPos = 0;               /* 64-bit position read from poslist */
+        int iOff = 0;               /* Current offset within position list */
+
+        rc = sqlite3Fts5IterPoslist(pCsr->pIter, 0, &pPos, &nPos, &dummy);
+        if( rc==SQLITE_OK ){
+          if( pTab->eType==FTS5_VOCAB_ROW ){
+            while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
+              pCsr->aVal[1]++;
+            }
+            pCsr->aVal[0]++;
+          }else{
+            int iCol = -1;
+            while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
+              int ii = FTS5_POS2COLUMN(iPos);
+              pCsr->aCnt[ii]++;
+              if( iCol!=ii ){
+                pCsr->aDoc[ii]++;
+                iCol = ii;
+              }
+            }
+          }
+          rc = sqlite3Fts5IterNextScan(pCsr->pIter);
+        }
+        if( rc==SQLITE_OK ){
+          zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
+          if( nTerm!=pCsr->term.n || memcmp(zTerm, pCsr->term.p, nTerm) ) break;
+          if( sqlite3Fts5IterEof(pCsr->pIter) ) break;
+        }
+      }
+    }
+  }
+
+  if( pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){
+    while( pCsr->aCnt[pCsr->iCol]==0 ) pCsr->iCol++;
+    pCsr->aVal[0] = pCsr->iCol;
+    pCsr->aVal[1] = pCsr->aDoc[pCsr->iCol];
+    pCsr->aVal[2] = pCsr->aCnt[pCsr->iCol];
+  }
+  return rc;
+}
+
+/*
+** This is the xFilter implementation for the virtual table.
+*/
+static int fts5VocabFilterMethod(
+  sqlite3_vtab_cursor *pCursor,   /* The cursor used for this query */
+  int idxNum,                     /* Strategy index */
+  const char *idxStr,             /* Unused */
+  int nVal,                       /* Number of elements in apVal */
+  sqlite3_value **apVal           /* Arguments for the indexing scheme */
+){
+  Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
+  int rc;
+  const int flags = FTS5INDEX_QUERY_SCAN;
+
+  fts5VocabResetCursor(pCsr);
+  rc = sqlite3Fts5IndexQuery(pCsr->pIndex, 0, 0, flags, 0, &pCsr->pIter);
+  if( rc==SQLITE_OK ){
+    rc = fts5VocabNextMethod(pCursor);
+  }
+
+  return rc;
+}
+
+/* 
+** This is the xEof method of the virtual table. SQLite calls this 
+** routine to find out if it has reached the end of a result set.
+*/
+static int fts5VocabEofMethod(sqlite3_vtab_cursor *pCursor){
+  Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
+  return pCsr->bEof;
+}
+
+static int fts5VocabColumnMethod(
+  sqlite3_vtab_cursor *pCursor,   /* Cursor to retrieve value from */
+  sqlite3_context *pCtx,          /* Context for sqlite3_result_xxx() calls */
+  int iCol                        /* Index of column to read value from */
+){
+  Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
+  switch( iCol ){
+    case 0: /* term */
+      sqlite3_result_text(
+          pCtx, (const char*)pCsr->term.p, pCsr->term.n, SQLITE_TRANSIENT
+      );
+      break;
+
+    default:
+      assert( iCol<4 && iCol>0 );
+      sqlite3_result_int64(pCtx, pCsr->aVal[iCol-1]);
+      break;
+  }
+  return SQLITE_OK;
+}
+
+/* 
+** This is the xRowid method. The SQLite core calls this routine to
+** retrieve the rowid for the current row of the result set. The
+** rowid should be written to *pRowid.
+*/
+static int fts5VocabRowidMethod(
+  sqlite3_vtab_cursor *pCursor, 
+  sqlite_int64 *pRowid
+){
+  Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
+  *pRowid = pCsr->rowid;
+  return SQLITE_OK;
+}
+
+static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){
+  static const sqlite3_module fts5Vocab = {
+    /* iVersion      */ 2,
+    /* xCreate       */ fts5VocabCreateMethod,
+    /* xConnect      */ fts5VocabConnectMethod,
+    /* xBestIndex    */ fts5VocabBestIndexMethod,
+    /* xDisconnect   */ fts5VocabDisconnectMethod,
+    /* xDestroy      */ fts5VocabDestroyMethod,
+    /* xOpen         */ fts5VocabOpenMethod,
+    /* xClose        */ fts5VocabCloseMethod,
+    /* xFilter       */ fts5VocabFilterMethod,
+    /* xNext         */ fts5VocabNextMethod,
+    /* xEof          */ fts5VocabEofMethod,
+    /* xColumn       */ fts5VocabColumnMethod,
+    /* xRowid        */ fts5VocabRowidMethod,
+    /* xUpdate       */ 0,
+    /* xBegin        */ 0,
+    /* xSync         */ 0,
+    /* xCommit       */ 0,
+    /* xRollback     */ 0,
+    /* xFindFunction */ 0,
+    /* xRename       */ 0,
+    /* xSavepoint    */ 0,
+    /* xRelease      */ 0,
+    /* xRollbackTo   */ 0,
+  };
+  void *p = (void*)pGlobal;
+
+  return sqlite3_create_module_v2(db, "fts5vocab", &fts5Vocab, p, 0);
+}
+
+
+
+
+    
+#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */
+
+/************** End of fts5.c ************************************************/
index d3f272c2b684b12c72322f27ca2d37f683df4b06..b42a740f9bc090decfd77364f6c318a30f8ab5ba 100644 (file)
@@ -111,9 +111,9 @@ extern "C" {
 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
 ** [sqlite_version()] and [sqlite_source_id()].
 */
-#define SQLITE_VERSION        "3.8.11.1"
-#define SQLITE_VERSION_NUMBER 3008011
-#define SQLITE_SOURCE_ID      "2015-07-29 20:00:57 cf538e2783e468bbc25e7cb2a9ee64d3e0e80b2f"
+#define SQLITE_VERSION        "3.9.0"
+#define SQLITE_VERSION_NUMBER 3009000
+#define SQLITE_SOURCE_ID      "2015-10-14 12:29:53 a721fc0d89495518fe5612e2e3bbc60befd2e90d"
 
 /*
 ** CAPI3REF: Run-Time Library Version Numbers
@@ -124,7 +124,7 @@ extern "C" {
 ** but are associated with the library instead of the header file.  ^(Cautious
 ** programmers might include assert() statements in their application to
 ** verify that values returned by these interfaces match the macros in
-** the header, and thus insure that the application is
+** the header, and thus ensure that the application is
 ** compiled with matching library and header files.
 **
 ** <blockquote><pre>
@@ -374,7 +374,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
 ** Restrictions:
 **
 ** <ul>
-** <li> The application must insure that the 1st parameter to sqlite3_exec()
+** <li> The application must ensure that the 1st parameter to sqlite3_exec()
 **      is a valid and open [database connection].
 ** <li> The application must not close the [database connection] specified by
 **      the 1st parameter to sqlite3_exec() while sqlite3_exec() is running.
@@ -477,6 +477,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
 #define SQLITE_IOERR_MMAP              (SQLITE_IOERR | (24<<8))
 #define SQLITE_IOERR_GETTEMPPATH       (SQLITE_IOERR | (25<<8))
 #define SQLITE_IOERR_CONVPATH          (SQLITE_IOERR | (26<<8))
+#define SQLITE_IOERR_VNODE             (SQLITE_IOERR | (27<<8))
 #define SQLITE_LOCKED_SHAREDCACHE      (SQLITE_LOCKED |  (1<<8))
 #define SQLITE_BUSY_RECOVERY           (SQLITE_BUSY   |  (1<<8))
 #define SQLITE_BUSY_SNAPSHOT           (SQLITE_BUSY   |  (2<<8))
@@ -1366,9 +1367,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void);
 ** applications and so this routine is usually not necessary.  It is
 ** provided to support rare applications with unusual needs.
 **
-** The sqlite3_config() interface is not threadsafe.  The application
-** must insure that no other SQLite interfaces are invoked by other
-** threads while sqlite3_config() is running.  Furthermore, sqlite3_config()
+** <b>The sqlite3_config() interface is not threadsafe. The application
+** must ensure that no other SQLite interfaces are invoked by other
+** threads while sqlite3_config() is running.</b>
+**
+** The sqlite3_config() interface
 ** may only be invoked prior to library initialization using
 ** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()].
 ** ^If sqlite3_config() is called after [sqlite3_initialize()] and before
@@ -3373,7 +3376,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
 **
 ** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the
 ** [prepared statement] S has been stepped at least once using 
-** [sqlite3_step(S)] but has not run to completion and/or has not 
+** [sqlite3_step(S)] but has neither run to completion (returned
+** [SQLITE_DONE] from [sqlite3_step(S)]) nor
 ** been reset using [sqlite3_reset(S)].  ^The sqlite3_stmt_busy(S)
 ** interface returns false if S is a NULL pointer.  If S is not a 
 ** NULL pointer and is not a pointer to a valid [prepared statement]
@@ -3626,7 +3630,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*,
 **
 ** See also: [sqlite3_bind_blob|sqlite3_bind()],
 ** [sqlite3_bind_parameter_count()], and
-** [sqlite3_bind_parameter_index()].
+** [sqlite3_bind_parameter_name()].
 */
 SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
 
@@ -4355,6 +4359,22 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16be(sqlite3_value*);
 SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value*);
 SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*);
 
+/*
+** CAPI3REF: Finding The Subtype Of SQL Values
+** METHOD: sqlite3_value
+**
+** The sqlite3_value_subtype(V) function returns the subtype for
+** an [application-defined SQL function] argument V.  The subtype
+** information can be used to pass a limited amount of context from
+** one SQL function to another.  Use the [sqlite3_result_subtype()]
+** routine to set the subtype for the return value of an SQL function.
+**
+** SQLite makes no use of subtype itself.  It merely passes the subtype
+** from the result of one [application-defined SQL function] into the
+** input of another.
+*/
+SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value*);
+
 /*
 ** CAPI3REF: Copy And Free SQL Values
 ** METHOD: sqlite3_value
@@ -4654,6 +4674,21 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context*, sqlite3_va
 SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context*, int n);
 SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
 
+
+/*
+** CAPI3REF: Setting The Subtype Of An SQL Function
+** METHOD: sqlite3_context
+**
+** The sqlite3_result_subtype(C,T) function causes the subtype of
+** the result from the [application-defined SQL function] with 
+** [sqlite3_context] C to be the value T.  Only the lower 8 bits 
+** of the subtype T are preserved in current versions of SQLite;
+** higher order bits are discarded.
+** The number of subtype bytes preserved by SQLite might increase
+** in future releases of SQLite.
+*/
+SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context*,unsigned int);
+
 /*
 ** CAPI3REF: Define New Collating Sequences
 ** METHOD: sqlite3
@@ -5599,13 +5634,31 @@ struct sqlite3_module {
 ** ^The estimatedRows value is an estimate of the number of rows that
 ** will be returned by the strategy.
 **
+** The xBestIndex method may optionally populate the idxFlags field with a 
+** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag -
+** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite
+** assumes that the strategy may visit at most one row. 
+**
+** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then
+** SQLite also assumes that if a call to the xUpdate() method is made as
+** part of the same statement to delete or update a virtual table row and the
+** implementation returns SQLITE_CONSTRAINT, then there is no need to rollback
+** any database changes. In other words, if the xUpdate() returns
+** SQLITE_CONSTRAINT, the database contents must be exactly as they were
+** before xUpdate was called. By contrast, if SQLITE_INDEX_SCAN_UNIQUE is not
+** set and xUpdate returns SQLITE_CONSTRAINT, any database changes made by
+** the xUpdate method are automatically rolled back by SQLite.
+**
 ** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
 ** structure for SQLite version 3.8.2. If a virtual table extension is
 ** used with an SQLite version earlier than 3.8.2, the results of attempting 
 ** to read or write the estimatedRows field are undefined (but are likely 
 ** to included crashing the application). The estimatedRows field should
 ** therefore only be used if [sqlite3_libversion_number()] returns a
-** value greater than or equal to 3008002.
+** value greater than or equal to 3008002. Similarly, the idxFlags field
+** was added for version 3.9.0. It may therefore only be used if
+** sqlite3_libversion_number() returns a value greater than or equal to
+** 3009000.
 */
 struct sqlite3_index_info {
   /* Inputs */
@@ -5633,8 +5686,15 @@ struct sqlite3_index_info {
   double estimatedCost;           /* Estimated cost of using this index */
   /* Fields below are only available in SQLite 3.8.2 and later */
   sqlite3_int64 estimatedRows;    /* Estimated number of rows returned */
+  /* Fields below are only available in SQLite 3.9.0 and later */
+  int idxFlags;              /* Mask of SQLITE_INDEX_SCAN_* flags */
 };
 
+/*
+** CAPI3REF: Virtual Table Scan Flags
+*/
+#define SQLITE_INDEX_SCAN_UNIQUE      1     /* Scan visits at most 1 row */
+
 /*
 ** CAPI3REF: Virtual Table Constraint Operator Codes
 **
@@ -6092,6 +6152,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
 ** <li>  SQLITE_MUTEX_STATIC_APP1
 ** <li>  SQLITE_MUTEX_STATIC_APP2
 ** <li>  SQLITE_MUTEX_STATIC_APP3
+** <li>  SQLITE_MUTEX_STATIC_VFS1
+** <li>  SQLITE_MUTEX_STATIC_VFS2
+** <li>  SQLITE_MUTEX_STATIC_VFS3
 ** </ul>
 **
 ** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE)
@@ -7858,3 +7921,524 @@ struct sqlite3_rtree_query_info {
 
 #endif  /* ifndef _SQLITE3RTREE_H_ */
 
+/*
+** 2014 May 31
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** Interfaces to extend FTS5. Using the interfaces defined in this file, 
+** FTS5 may be extended with:
+**
+**     * custom tokenizers, and
+**     * custom auxiliary functions.
+*/
+
+
+#ifndef _FTS5_H
+#define _FTS5_H
+
+#include "sqlite3.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*************************************************************************
+** CUSTOM AUXILIARY FUNCTIONS
+**
+** Virtual table implementations may overload SQL functions by implementing
+** the sqlite3_module.xFindFunction() method.
+*/
+
+typedef struct Fts5ExtensionApi Fts5ExtensionApi;
+typedef struct Fts5Context Fts5Context;
+typedef struct Fts5PhraseIter Fts5PhraseIter;
+
+typedef void (*fts5_extension_function)(
+  const Fts5ExtensionApi *pApi,   /* API offered by current FTS version */
+  Fts5Context *pFts,              /* First arg to pass to pApi functions */
+  sqlite3_context *pCtx,          /* Context for returning result/error */
+  int nVal,                       /* Number of values in apVal[] array */
+  sqlite3_value **apVal           /* Array of trailing arguments */
+);
+
+struct Fts5PhraseIter {
+  const unsigned char *a;
+  const unsigned char *b;
+};
+
+/*
+** EXTENSION API FUNCTIONS
+**
+** xUserData(pFts):
+**   Return a copy of the context pointer the extension function was 
+**   registered with.
+**
+** xColumnTotalSize(pFts, iCol, pnToken):
+**   If parameter iCol is less than zero, set output variable *pnToken
+**   to the total number of tokens in the FTS5 table. Or, if iCol is
+**   non-negative but less than the number of columns in the table, return
+**   the total number of tokens in column iCol, considering all rows in 
+**   the FTS5 table.
+**
+**   If parameter iCol is greater than or equal to the number of columns
+**   in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
+**   an OOM condition or IO error), an appropriate SQLite error code is 
+**   returned.
+**
+** xColumnCount(pFts):
+**   Return the number of columns in the table.
+**
+** xColumnSize(pFts, iCol, pnToken):
+**   If parameter iCol is less than zero, set output variable *pnToken
+**   to the total number of tokens in the current row. Or, if iCol is
+**   non-negative but less than the number of columns in the table, set
+**   *pnToken to the number of tokens in column iCol of the current row.
+**
+**   If parameter iCol is greater than or equal to the number of columns
+**   in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
+**   an OOM condition or IO error), an appropriate SQLite error code is 
+**   returned.
+**
+** xColumnText:
+**   This function attempts to retrieve the text of column iCol of the
+**   current document. If successful, (*pz) is set to point to a buffer
+**   containing the text in utf-8 encoding, (*pn) is set to the size in bytes
+**   (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
+**   if an error occurs, an SQLite error code is returned and the final values
+**   of (*pz) and (*pn) are undefined.
+**
+** xPhraseCount:
+**   Returns the number of phrases in the current query expression.
+**
+** xPhraseSize:
+**   Returns the number of tokens in phrase iPhrase of the query. Phrases
+**   are numbered starting from zero.
+**
+** xInstCount:
+**   Set *pnInst to the total number of occurrences of all phrases within
+**   the query within the current row. Return SQLITE_OK if successful, or
+**   an error code (i.e. SQLITE_NOMEM) if an error occurs.
+**
+** xInst:
+**   Query for the details of phrase match iIdx within the current row.
+**   Phrase matches are numbered starting from zero, so the iIdx argument
+**   should be greater than or equal to zero and smaller than the value
+**   output by xInstCount().
+**
+**   Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) 
+**   if an error occurs.
+**
+** xRowid:
+**   Returns the rowid of the current row.
+**
+** xTokenize:
+**   Tokenize text using the tokenizer belonging to the FTS5 table.
+**
+** xQueryPhrase(pFts5, iPhrase, pUserData, xCallback):
+**   This API function is used to query the FTS table for phrase iPhrase
+**   of the current query. Specifically, a query equivalent to:
+**
+**       ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid
+**
+**   with $p set to a phrase equivalent to the phrase iPhrase of the
+**   current query is executed. For each row visited, the callback function
+**   passed as the fourth argument is invoked. The context and API objects 
+**   passed to the callback function may be used to access the properties of
+**   each matched row. Invoking Api.xUserData() returns a copy of the pointer
+**   passed as the third argument to pUserData.
+**
+**   If the callback function returns any value other than SQLITE_OK, the
+**   query is abandoned and the xQueryPhrase function returns immediately.
+**   If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK.
+**   Otherwise, the error code is propagated upwards.
+**
+**   If the query runs to completion without incident, SQLITE_OK is returned.
+**   Or, if some error occurs before the query completes or is aborted by
+**   the callback, an SQLite error code is returned.
+**
+**
+** xSetAuxdata(pFts5, pAux, xDelete)
+**
+**   Save the pointer passed as the second argument as the extension functions 
+**   "auxiliary data". The pointer may then be retrieved by the current or any
+**   future invocation of the same fts5 extension function made as part of
+**   of the same MATCH query using the xGetAuxdata() API.
+**
+**   Each extension function is allocated a single auxiliary data slot for
+**   each FTS query (MATCH expression). If the extension function is invoked 
+**   more than once for a single FTS query, then all invocations share a 
+**   single auxiliary data context.
+**
+**   If there is already an auxiliary data pointer when this function is
+**   invoked, then it is replaced by the new pointer. If an xDelete callback
+**   was specified along with the original pointer, it is invoked at this
+**   point.
+**
+**   The xDelete callback, if one is specified, is also invoked on the
+**   auxiliary data pointer after the FTS5 query has finished.
+**
+**   If an error (e.g. an OOM condition) occurs within this function, an
+**   the auxiliary data is set to NULL and an error code returned. If the
+**   xDelete parameter was not NULL, it is invoked on the auxiliary data
+**   pointer before returning.
+**
+**
+** xGetAuxdata(pFts5, bClear)
+**
+**   Returns the current auxiliary data pointer for the fts5 extension 
+**   function. See the xSetAuxdata() method for details.
+**
+**   If the bClear argument is non-zero, then the auxiliary data is cleared
+**   (set to NULL) before this function returns. In this case the xDelete,
+**   if any, is not invoked.
+**
+**
+** xRowCount(pFts5, pnRow)
+**
+**   This function is used to retrieve the total number of rows in the table.
+**   In other words, the same value that would be returned by:
+**
+**        SELECT count(*) FROM ftstable;
+**
+** xPhraseFirst()
+**   This function is used, along with type Fts5PhraseIter and the xPhraseNext
+**   method, to iterate through all instances of a single query phrase within
+**   the current row. This is the same information as is accessible via the
+**   xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient
+**   to use, this API may be faster under some circumstances. To iterate 
+**   through instances of phrase iPhrase, use the following code:
+**
+**       Fts5PhraseIter iter;
+**       int iCol, iOff;
+**       for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
+**           iOff>=0;
+**           pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
+**       ){
+**         // An instance of phrase iPhrase at offset iOff of column iCol
+**       }
+**
+**   The Fts5PhraseIter structure is defined above. Applications should not
+**   modify this structure directly - it should only be used as shown above
+**   with the xPhraseFirst() and xPhraseNext() API methods.
+**
+** xPhraseNext()
+**   See xPhraseFirst above.
+*/
+struct Fts5ExtensionApi {
+  int iVersion;                   /* Currently always set to 1 */
+
+  void *(*xUserData)(Fts5Context*);
+
+  int (*xColumnCount)(Fts5Context*);
+  int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
+  int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken);
+
+  int (*xTokenize)(Fts5Context*, 
+    const char *pText, int nText, /* Text to tokenize */
+    void *pCtx,                   /* Context passed to xToken() */
+    int (*xToken)(void*, int, const char*, int, int, int)       /* Callback */
+  );
+
+  int (*xPhraseCount)(Fts5Context*);
+  int (*xPhraseSize)(Fts5Context*, int iPhrase);
+
+  int (*xInstCount)(Fts5Context*, int *pnInst);
+  int (*xInst)(Fts5Context*, int iIdx, int *piPhrase, int *piCol, int *piOff);
+
+  sqlite3_int64 (*xRowid)(Fts5Context*);
+  int (*xColumnText)(Fts5Context*, int iCol, const char **pz, int *pn);
+  int (*xColumnSize)(Fts5Context*, int iCol, int *pnToken);
+
+  int (*xQueryPhrase)(Fts5Context*, int iPhrase, void *pUserData,
+    int(*)(const Fts5ExtensionApi*,Fts5Context*,void*)
+  );
+  int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
+  void *(*xGetAuxdata)(Fts5Context*, int bClear);
+
+  void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
+  void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
+};
+
+/* 
+** CUSTOM AUXILIARY FUNCTIONS
+*************************************************************************/
+
+/*************************************************************************
+** CUSTOM TOKENIZERS
+**
+** Applications may also register custom tokenizer types. A tokenizer 
+** is registered by providing fts5 with a populated instance of the 
+** following structure. All structure methods must be defined, setting
+** any member of the fts5_tokenizer struct to NULL leads to undefined
+** behaviour. The structure methods are expected to function as follows:
+**
+** xCreate:
+**   This function is used to allocate and inititalize a tokenizer instance.
+**   A tokenizer instance is required to actually tokenize text.
+**
+**   The first argument passed to this function is a copy of the (void*)
+**   pointer provided by the application when the fts5_tokenizer object
+**   was registered with FTS5 (the third argument to xCreateTokenizer()). 
+**   The second and third arguments are an array of nul-terminated strings
+**   containing the tokenizer arguments, if any, specified following the
+**   tokenizer name as part of the CREATE VIRTUAL TABLE statement used
+**   to create the FTS5 table.
+**
+**   The final argument is an output variable. If successful, (*ppOut) 
+**   should be set to point to the new tokenizer handle and SQLITE_OK
+**   returned. If an error occurs, some value other than SQLITE_OK should
+**   be returned. In this case, fts5 assumes that the final value of *ppOut 
+**   is undefined.
+**
+** xDelete:
+**   This function is invoked to delete a tokenizer handle previously
+**   allocated using xCreate(). Fts5 guarantees that this function will
+**   be invoked exactly once for each successful call to xCreate().
+**
+** xTokenize:
+**   This function is expected to tokenize the nText byte string indicated 
+**   by argument pText. pText may or may not be nul-terminated. The first
+**   argument passed to this function is a pointer to an Fts5Tokenizer object
+**   returned by an earlier call to xCreate().
+**
+**   The second argument indicates the reason that FTS5 is requesting
+**   tokenization of the supplied text. This is always one of the following
+**   four values:
+**
+**   <ul><li> <b>FTS5_TOKENIZE_DOCUMENT</b> - A document is being inserted into
+**            or removed from the FTS table. The tokenizer is being invoked to
+**            determine the set of tokens to add to (or delete from) the
+**            FTS index.
+**
+**       <li> <b>FTS5_TOKENIZE_QUERY</b> - A MATCH query is being executed 
+**            against the FTS index. The tokenizer is being called to tokenize 
+**            a bareword or quoted string specified as part of the query.
+**
+**       <li> <b>(FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX)</b> - Same as
+**            FTS5_TOKENIZE_QUERY, except that the bareword or quoted string is
+**            followed by a "*" character, indicating that the last token
+**            returned by the tokenizer will be treated as a token prefix.
+**
+**       <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to 
+**            satisfy an fts5_api.xTokenize() request made by an auxiliary
+**            function. Or an fts5_api.xColumnSize() request made by the same
+**            on a columnsize=0 database.  
+**   </ul>
+**
+**   For each token in the input string, the supplied callback xToken() must
+**   be invoked. The first argument to it should be a copy of the pointer
+**   passed as the second argument to xTokenize(). The third and fourth
+**   arguments are a pointer to a buffer containing the token text, and the
+**   size of the token in bytes. The 4th and 5th arguments are the byte offsets
+**   of the first byte of and first byte immediately following the text from
+**   which the token is derived within the input.
+**
+**   The second argument passed to the xToken() callback ("tflags") should
+**   normally be set to 0. The exception is if the tokenizer supports 
+**   synonyms. In this case see the discussion below for details.
+**
+**   FTS5 assumes the xToken() callback is invoked for each token in the 
+**   order that they occur within the input text.
+**
+**   If an xToken() callback returns any value other than SQLITE_OK, then
+**   the tokenization should be abandoned and the xTokenize() method should
+**   immediately return a copy of the xToken() return value. Or, if the
+**   input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally,
+**   if an error occurs with the xTokenize() implementation itself, it
+**   may abandon the tokenization and return any error code other than
+**   SQLITE_OK or SQLITE_DONE.
+**
+** SYNONYM SUPPORT
+**
+**   Custom tokenizers may also support synonyms. Consider a case in which a
+**   user wishes to query for a phrase such as "first place". Using the 
+**   built-in tokenizers, the FTS5 query 'first + place' will match instances
+**   of "first place" within the document set, but not alternative forms
+**   such as "1st place". In some applications, it would be better to match
+**   all instances of "first place" or "1st place" regardless of which form
+**   the user specified in the MATCH query text.
+**
+**   There are several ways to approach this in FTS5:
+**
+**   <ol><li> By mapping all synonyms to a single token. In this case, the 
+**            In the above example, this means that the tokenizer returns the
+**            same token for inputs "first" and "1st". Say that token is in
+**            fact "first", so that when the user inserts the document "I won
+**            1st place" entries are added to the index for tokens "i", "won",
+**            "first" and "place". If the user then queries for '1st + place',
+**            the tokenizer substitutes "first" for "1st" and the query works
+**            as expected.
+**
+**       <li> By adding multiple synonyms for a single term to the FTS index.
+**            In this case, when tokenizing query text, the tokenizer may 
+**            provide multiple synonyms for a single term within the document.
+**            FTS5 then queries the index for each synonym individually. For
+**            example, faced with the query:
+**
+**   <codeblock>
+**     ... MATCH 'first place'</codeblock>
+**
+**            the tokenizer offers both "1st" and "first" as synonyms for the
+**            first token in the MATCH query and FTS5 effectively runs a query 
+**            similar to:
+**
+**   <codeblock>
+**     ... MATCH '(first OR 1st) place'</codeblock>
+**
+**            except that, for the purposes of auxiliary functions, the query
+**            still appears to contain just two phrases - "(first OR 1st)" 
+**            being treated as a single phrase.
+**
+**       <li> By adding multiple synonyms for a single term to the FTS index.
+**            Using this method, when tokenizing document text, the tokenizer
+**            provides multiple synonyms for each token. So that when a 
+**            document such as "I won first place" is tokenized, entries are
+**            added to the FTS index for "i", "won", "first", "1st" and
+**            "place".
+**
+**            This way, even if the tokenizer does not provide synonyms
+**            when tokenizing query text (it should not - to do would be
+**            inefficient), it doesn't matter if the user queries for 
+**            'first + place' or '1st + place', as there are entires in the
+**            FTS index corresponding to both forms of the first token.
+**   </ol>
+**
+**   Whether it is parsing document or query text, any call to xToken that
+**   specifies a <i>tflags</i> argument with the FTS5_TOKEN_COLOCATED bit
+**   is considered to supply a synonym for the previous token. For example,
+**   when parsing the document "I won first place", a tokenizer that supports
+**   synonyms would call xToken() 5 times, as follows:
+**
+**   <codeblock>
+**       xToken(pCtx, 0, "i",                      1,  0,  1);
+**       xToken(pCtx, 0, "won",                    3,  2,  5);
+**       xToken(pCtx, 0, "first",                  5,  6, 11);
+**       xToken(pCtx, FTS5_TOKEN_COLOCATED, "1st", 3,  6, 11);
+**       xToken(pCtx, 0, "place",                  5, 12, 17);
+**</codeblock>
+**
+**   It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time
+**   xToken() is called. Multiple synonyms may be specified for a single token
+**   by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence. 
+**   There is no limit to the number of synonyms that may be provided for a
+**   single token.
+**
+**   In many cases, method (1) above is the best approach. It does not add 
+**   extra data to the FTS index or require FTS5 to query for multiple terms,
+**   so it is efficient in terms of disk space and query speed. However, it
+**   does not support prefix queries very well. If, as suggested above, the
+**   token "first" is subsituted for "1st" by the tokenizer, then the query:
+**
+**   <codeblock>
+**     ... MATCH '1s*'</codeblock>
+**
+**   will not match documents that contain the token "1st" (as the tokenizer
+**   will probably not map "1s" to any prefix of "first").
+**
+**   For full prefix support, method (3) may be preferred. In this case, 
+**   because the index contains entries for both "first" and "1st", prefix
+**   queries such as 'fi*' or '1s*' will match correctly. However, because
+**   extra entries are added to the FTS index, this method uses more space
+**   within the database.
+**
+**   Method (2) offers a midpoint between (1) and (3). Using this method,
+**   a query such as '1s*' will match documents that contain the literal 
+**   token "1st", but not "first" (assuming the tokenizer is not able to
+**   provide synonyms for prefixes). However, a non-prefix query like '1st'
+**   will match against "1st" and "first". This method does not require
+**   extra disk space, as no extra entries are added to the FTS index. 
+**   On the other hand, it may require more CPU cycles to run MATCH queries,
+**   as separate queries of the FTS index are required for each synonym.
+**
+**   When using methods (2) or (3), it is important that the tokenizer only
+**   provide synonyms when tokenizing document text (method (2)) or query
+**   text (method (3)), not both. Doing so will not cause any errors, but is
+**   inefficient.
+*/
+typedef struct Fts5Tokenizer Fts5Tokenizer;
+typedef struct fts5_tokenizer fts5_tokenizer;
+struct fts5_tokenizer {
+  int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
+  void (*xDelete)(Fts5Tokenizer*);
+  int (*xTokenize)(Fts5Tokenizer*, 
+      void *pCtx,
+      int flags,            /* Mask of FTS5_TOKENIZE_* flags */
+      const char *pText, int nText, 
+      int (*xToken)(
+        void *pCtx,         /* Copy of 2nd argument to xTokenize() */
+        int tflags,         /* Mask of FTS5_TOKEN_* flags */
+        const char *pToken, /* Pointer to buffer containing token */
+        int nToken,         /* Size of token in bytes */
+        int iStart,         /* Byte offset of token within input text */
+        int iEnd            /* Byte offset of end of token within input text */
+      )
+  );
+};
+
+/* Flags that may be passed as the third argument to xTokenize() */
+#define FTS5_TOKENIZE_QUERY     0x0001
+#define FTS5_TOKENIZE_PREFIX    0x0002
+#define FTS5_TOKENIZE_DOCUMENT  0x0004
+#define FTS5_TOKENIZE_AUX       0x0008
+
+/* Flags that may be passed by the tokenizer implementation back to FTS5
+** as the third argument to the supplied xToken callback. */
+#define FTS5_TOKEN_COLOCATED    0x0001      /* Same position as prev. token */
+
+/*
+** END OF CUSTOM TOKENIZERS
+*************************************************************************/
+
+/*************************************************************************
+** FTS5 EXTENSION REGISTRATION API
+*/
+typedef struct fts5_api fts5_api;
+struct fts5_api {
+  int iVersion;                   /* Currently always set to 2 */
+
+  /* Create a new tokenizer */
+  int (*xCreateTokenizer)(
+    fts5_api *pApi,
+    const char *zName,
+    void *pContext,
+    fts5_tokenizer *pTokenizer,
+    void (*xDestroy)(void*)
+  );
+
+  /* Find an existing tokenizer */
+  int (*xFindTokenizer)(
+    fts5_api *pApi,
+    const char *zName,
+    void **ppContext,
+    fts5_tokenizer *pTokenizer
+  );
+
+  /* Create a new auxiliary function */
+  int (*xCreateFunction)(
+    fts5_api *pApi,
+    const char *zName,
+    void *pContext,
+    fts5_extension_function xFunction,
+    void (*xDestroy)(void*)
+  );
+};
+
+/*
+** END OF REGISTRATION API
+*************************************************************************/
+
+#ifdef __cplusplus
+}  /* end of the 'extern "C"' block */
+#endif
+
+#endif /* _FTS5_H */
+
+
index 48a5bf744b05633dac72049d458da76a330cbcaa..017ea308b1a7d6d6ce7e96f6a4a91a6e828516c5 100644 (file)
@@ -272,6 +272,9 @@ struct sqlite3_api_routines {
   void (*value_free)(sqlite3_value*);
   int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);
   int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);
+  /* Version 3.9.0 and later */
+  unsigned int (*value_subtype)(sqlite3_value*);
+  void (*result_subtype)(sqlite3_context*,unsigned int);
 };
 
 /*
@@ -285,7 +288,7 @@ struct sqlite3_api_routines {
 ** the API.  So the redefinition macros are only valid if the
 ** SQLITE_CORE macros is undefined.
 */
-#ifndef SQLITE_CORE
+#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
 #define sqlite3_aggregate_context      sqlite3_api->aggregate_context
 #ifndef SQLITE_OMIT_DEPRECATED
 #define sqlite3_aggregate_count        sqlite3_api->aggregate_count
@@ -412,6 +415,7 @@ struct sqlite3_api_routines {
 #define sqlite3_value_text16le         sqlite3_api->value_text16le
 #define sqlite3_value_type             sqlite3_api->value_type
 #define sqlite3_vmprintf               sqlite3_api->vmprintf
+#define sqlite3_vsnprintf              sqlite3_api->vsnprintf
 #define sqlite3_overload_function      sqlite3_api->overload_function
 #define sqlite3_prepare_v2             sqlite3_api->prepare_v2
 #define sqlite3_prepare16_v2           sqlite3_api->prepare16_v2
@@ -507,9 +511,12 @@ struct sqlite3_api_routines {
 #define sqlite3_value_free             sqlite3_api->value_free
 #define sqlite3_result_zeroblob64      sqlite3_api->result_zeroblob64
 #define sqlite3_bind_zeroblob64        sqlite3_api->bind_zeroblob64
-#endif /* SQLITE_CORE */
+/* Version 3.9.0 and later */
+#define sqlite3_value_subtype          sqlite3_api->value_subtype
+#define sqlite3_result_subtype         sqlite3_api->result_subtype
+#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
 
-#ifndef SQLITE_CORE
+#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
   /* This case when the file really is being compiled as a loadable 
   ** extension */
 # define SQLITE_EXTENSION_INIT1     const sqlite3_api_routines *sqlite3_api=0;