/ Check-in [d2ccf7fc]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Merge in all changes to the trunk through version 3.7.4rc3.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | apple-osx
Files: files | file ages | folders
SHA1: d2ccf7fc0673e875ff7b84cd37b89c65df4bec7f
User & Date: drh 2010-12-07 15:49:03
Context
2011-01-27
18:48
Pull in all the changes from trunk up through the version 3.7.5 release candidate 1. check-in: 09d6c91d user: drh tags: apple-osx
2010-12-07
15:49
Merge in all changes to the trunk through version 3.7.4rc3. check-in: d2ccf7fc user: drh tags: apple-osx
14:59
Version 3.7.4 release candidate 3 check-in: 11c74c0d user: drh tags: trunk
2010-11-19
23:50
Merge all the latest changes from the trunk into the apple-osx branch. check-in: c8bc057c user: drh tags: apple-osx
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to Makefile.in.

   372    372     $(TOP)/src/test_onefile.c \
   373    373     $(TOP)/src/test_osinst.c \
   374    374     $(TOP)/src/test_pcache.c \
   375    375     $(TOP)/src/test_quota.c \
   376    376     $(TOP)/src/test_rtree.c \
   377    377     $(TOP)/src/test_schema.c \
   378    378     $(TOP)/src/test_server.c \
          379  +  $(TOP)/src/test_superlock.c \
   379    380     $(TOP)/src/test_stat.c \
   380    381     $(TOP)/src/test_tclvar.c \
   381    382     $(TOP)/src/test_thread.c \
   382    383     $(TOP)/src/test_vfs.c \
   383    384     $(TOP)/src/test_wsd.c
   384    385   
   385    386   # Source code to the library files needed by the test fixture

Changes to ext/fts3/fts3.c.

   652    652     const char *zCsr = z;
   653    653   
   654    654     while( *zCsr!='=' ){
   655    655       if( *zCsr=='\0' ) return 0;
   656    656       zCsr++;
   657    657     }
   658    658   
   659         -  *pnKey = zCsr-z;
          659  +  *pnKey = (int)(zCsr-z);
   660    660     zValue = sqlite3_mprintf("%s", &zCsr[1]);
   661    661     if( zValue ){
   662    662       sqlite3Fts3Dequote(zValue);
   663    663     }
   664    664     *pzValue = zValue;
   665    665     return 1;
   666    666   }
................................................................................
   707    707     );
   708    708   
   709    709     nDb = (int)strlen(argv[1]) + 1;
   710    710     nName = (int)strlen(argv[2]) + 1;
   711    711   
   712    712     aCol = (const char **)sqlite3_malloc(sizeof(const char *) * (argc-2) );
   713    713     if( !aCol ) return SQLITE_NOMEM;
   714         -  memset(aCol, 0, sizeof(const char *) * (argc-2));
          714  +  memset((void *)aCol, 0, sizeof(const char *) * (argc-2));
   715    715   
   716    716     /* Loop through all of the arguments passed by the user to the FTS3/4
   717    717     ** module (i.e. all the column names and special arguments). This loop
   718    718     ** does the following:
   719    719     **
   720    720     **   + Figures out the number of columns the FTSX table will have, and
   721    721     **     the number of bytes of space that must be allocated to store copies
................................................................................
   839    839     fts3DatabasePageSize(&rc, p);
   840    840   
   841    841     /* Declare the table schema to SQLite. */
   842    842     fts3DeclareVtab(&rc, p);
   843    843   
   844    844   fts3_init_out:
   845    845   
   846         -  sqlite3_free(aCol);
          846  +  sqlite3_free((void *)aCol);
   847    847     if( rc!=SQLITE_OK ){
   848    848       if( p ){
   849    849         fts3DisconnectMethod((sqlite3_vtab *)p);
   850    850       }else if( pTokenizer ){
   851    851         pTokenizer->pModule->xDestroy(pTokenizer);
   852    852       }
   853    853     }else{
................................................................................
  1018   1018   ** If piLast is not NULL, then *piLast is set to the right-most child node
  1019   1019   ** that heads a sub-tree that may contain a term for which zTerm/nTerm is
  1020   1020   ** a prefix.
  1021   1021   **
  1022   1022   ** If an OOM error occurs, SQLITE_NOMEM is returned. Otherwise, SQLITE_OK.
  1023   1023   */
  1024   1024   static int fts3ScanInteriorNode(
  1025         -  Fts3Table *p,                   /* Virtual table handle */
  1026   1025     const char *zTerm,              /* Term to select leaves for */
  1027   1026     int nTerm,                      /* Size of term zTerm in bytes */
  1028   1027     const char *zNode,              /* Buffer containing segment interior node */
  1029   1028     int nNode,                      /* Size of buffer at zNode */
  1030   1029     sqlite3_int64 *piFirst,         /* OUT: Selected child node */
  1031   1030     sqlite3_int64 *piLast           /* OUT: Selected child node */
  1032   1031   ){
................................................................................
  1049   1048     ** either more than 20 bytes of allocated space following the nNode bytes of
  1050   1049     ** contents, or two zero bytes. Or, if the node is read from the %_segments
  1051   1050     ** table, then there are always 20 bytes of zeroed padding following the
  1052   1051     ** nNode bytes of content (see sqlite3Fts3ReadBlock() for details).
  1053   1052     */
  1054   1053     zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
  1055   1054     zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
  1056         -  if( zCsr>=zEnd ){
         1055  +  if( zCsr>zEnd ){
  1057   1056       return SQLITE_CORRUPT;
  1058   1057     }
  1059   1058     
  1060   1059     while( zCsr<zEnd && (piFirst || piLast) ){
  1061   1060       int cmp;                      /* memcmp() result */
  1062   1061       int nSuffix;                  /* Size of term suffix */
  1063   1062       int nPrefix = 0;              /* Size of term prefix */
................................................................................
  1153   1152   ){
  1154   1153     int rc;                         /* Return code */
  1155   1154     int iHeight;                    /* Height of this node in tree */
  1156   1155   
  1157   1156     assert( piLeaf || piLeaf2 );
  1158   1157   
  1159   1158     sqlite3Fts3GetVarint32(zNode, &iHeight);
  1160         -  rc = fts3ScanInteriorNode(p, zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2);
         1159  +  rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2);
  1161   1160     assert( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) );
  1162   1161   
  1163   1162     if( rc==SQLITE_OK && iHeight>1 ){
  1164   1163       char *zBlob = 0;              /* Blob read from %_segments table */
  1165   1164       int nBlob;                    /* Size of zBlob in bytes */
  1166   1165   
  1167   1166       if( piLeaf && piLeaf2 && (*piLeaf!=*piLeaf2) ){
................................................................................
  1952   1951   ** Free an Fts3SegReaderArray object. Also free all seg-readers in the
  1953   1952   ** array (using sqlite3Fts3SegReaderFree()).
  1954   1953   */
  1955   1954   static void fts3SegReaderArrayFree(Fts3SegReaderArray *pArray){
  1956   1955     if( pArray ){
  1957   1956       int i;
  1958   1957       for(i=0; i<pArray->nSegment; i++){
  1959         -      sqlite3Fts3SegReaderFree(0, pArray->apSegment[i]);
         1958  +      sqlite3Fts3SegReaderFree(pArray->apSegment[i]);
  1960   1959       }
  1961   1960       sqlite3_free(pArray);
  1962   1961     }
  1963   1962   }
  1964   1963   
  1965   1964   static int fts3SegReaderArrayAdd(
  1966   1965     Fts3SegReaderArray **ppArray, 
................................................................................
  1970   1969   
  1971   1970     if( !pArray || pArray->nAlloc==pArray->nSegment ){
  1972   1971       int nNew = (pArray ? pArray->nAlloc+16 : 16);
  1973   1972       pArray = (Fts3SegReaderArray *)sqlite3_realloc(pArray, 
  1974   1973           sizeof(Fts3SegReaderArray) + (nNew-1) * sizeof(Fts3SegReader*)
  1975   1974       );
  1976   1975       if( !pArray ){
  1977         -      sqlite3Fts3SegReaderFree(0, pNew);
         1976  +      sqlite3Fts3SegReaderFree(pNew);
  1978   1977         return SQLITE_NOMEM;
  1979   1978       }
  1980   1979       if( nNew==16 ){
  1981   1980         pArray->nSegment = 0;
  1982   1981         pArray->nCost = 0;
  1983   1982       }
  1984   1983       pArray->nAlloc = nNew;
................................................................................
  2023   2022       int nRoot = sqlite3_column_bytes(pStmt, 4);
  2024   2023       char const *zRoot = sqlite3_column_blob(pStmt, 4);
  2025   2024       if( sqlite3_column_int64(pStmt, 1)==0 ){
  2026   2025         /* The entire segment is stored on the root node (which must be a
  2027   2026         ** leaf). Do not bother inspecting any data in this case, just
  2028   2027         ** create a Fts3SegReader to scan the single leaf. 
  2029   2028         */
  2030         -      rc = sqlite3Fts3SegReaderNew(p, iAge, 0, 0, 0, zRoot, nRoot, &pNew);
         2029  +      rc = sqlite3Fts3SegReaderNew(iAge, 0, 0, 0, zRoot, nRoot, &pNew);
  2031   2030       }else{
  2032   2031         sqlite3_int64 i1;           /* First leaf that may contain zTerm */
  2033   2032         sqlite3_int64 i2;           /* Final leaf that may contain zTerm */
  2034   2033         rc = fts3SelectLeaf(p, zTerm, nTerm, zRoot, nRoot, &i1, (isPrefix?&i2:0));
  2035   2034         if( isPrefix==0 ) i2 = i1;
  2036   2035         if( rc==SQLITE_OK ){
  2037         -        rc = sqlite3Fts3SegReaderNew(p, iAge, i1, i2, 0, 0, 0, &pNew);
         2036  +        rc = sqlite3Fts3SegReaderNew(iAge, i1, i2, 0, 0, 0, &pNew);
  2038   2037         }
  2039   2038       }
  2040   2039       assert( (pNew==0)==(rc!=SQLITE_OK) );
  2041   2040   
  2042   2041       /* If a new Fts3SegReader was allocated, add it to the array. */
  2043   2042       if( rc==SQLITE_OK ){
  2044   2043         rc = fts3SegReaderArrayAdd(&pArray, pNew);
................................................................................
  2196   2195       while( p<aEnd ){
  2197   2196         sqlite3_int64 delta;
  2198   2197         p += sqlite3Fts3GetVarint(p, &delta);
  2199   2198         fts3PoslistCopy(0, &p);
  2200   2199         pOut += sqlite3Fts3PutVarint(pOut, delta);
  2201   2200       }
  2202   2201   
  2203         -    *pnList = (pOut - aList);
         2202  +    *pnList = (int)(pOut - aList);
  2204   2203     }
  2205   2204   }
  2206   2205   
  2207   2206   /* 
  2208   2207   ** Return a DocList corresponding to the phrase *pPhrase.
  2209   2208   **
  2210   2209   ** If this function returns SQLITE_OK, but *pnOut is set to a negative value,
................................................................................
  2250   2249           if( rc!=SQLITE_OK ) return rc;
  2251   2250         }
  2252   2251       }
  2253   2252     }
  2254   2253   
  2255   2254     for(ii=0; ii<pPhrase->nToken; ii++){
  2256   2255       Fts3PhraseToken *pTok;        /* Token to find doclist for */
  2257         -    int iTok;                     /* The token being queried this iteration */
  2258         -    char *pList;                  /* Pointer to token doclist */
  2259         -    int nList;                    /* Size of buffer at pList */
         2256  +    int iTok = 0;                 /* The token being queried this iteration */
         2257  +    char *pList = 0;              /* Pointer to token doclist */
         2258  +    int nList = 0;                /* Size of buffer at pList */
  2260   2259   
  2261   2260       /* Select a token to process. If this is an xFilter() call, then tokens 
  2262   2261       ** are processed in order from least to most costly. Otherwise, tokens 
  2263   2262       ** are processed in the order in which they occur in the phrase.
  2264   2263       */
  2265   2264       if( pCsr->eEvalmode==FTS3_EVAL_MATCHINFO ){
  2266   2265         assert( isReqPos );
................................................................................
  2294   2293           break;
  2295   2294         }
  2296   2295       }
  2297   2296   
  2298   2297       if( pCsr->eEvalmode==FTS3_EVAL_NEXT && pTok->pDeferred ){
  2299   2298         rc = fts3DeferredTermSelect(pTok->pDeferred, isTermPos, &nList, &pList);
  2300   2299       }else{
  2301         -      assert( pTok->pArray );
  2302         -      rc = fts3TermSelect(p, pTok, iCol, isTermPos, &nList, &pList);
         2300  +      if( pTok->pArray ){
         2301  +        rc = fts3TermSelect(p, pTok, iCol, isTermPos, &nList, &pList);
         2302  +      }
  2303   2303         pTok->bFulltext = 1;
  2304   2304       }
  2305   2305       assert( rc!=SQLITE_OK || pCsr->eEvalmode || pTok->pArray==0 );
  2306   2306       if( rc!=SQLITE_OK ) break;
  2307   2307   
  2308   2308       if( isFirst ){
  2309   2309         pOut = pList;
................................................................................
  2523   2523   static int fts3ExprCost(Fts3Expr *pExpr){
  2524   2524     int nCost;                      /* Return value */
  2525   2525     if( pExpr->eType==FTSQUERY_PHRASE ){
  2526   2526       Fts3Phrase *pPhrase = pExpr->pPhrase;
  2527   2527       int ii;
  2528   2528       nCost = 0;
  2529   2529       for(ii=0; ii<pPhrase->nToken; ii++){
  2530         -      nCost += pPhrase->aToken[ii].pArray->nCost;
         2530  +      Fts3SegReaderArray *pArray = pPhrase->aToken[ii].pArray;
         2531  +      if( pArray ){
         2532  +        nCost += pPhrase->aToken[ii].pArray->nCost;
         2533  +      }
  2531   2534       }
  2532   2535     }else{
  2533   2536       nCost = fts3ExprCost(pExpr->pLeft) + fts3ExprCost(pExpr->pRight);
  2534   2537     }
  2535   2538     return nCost;
  2536   2539   }
  2537   2540   
................................................................................
  2551   2554     ExprAndCost **ppExprCost        /* OUT: Write to *ppExprCost */
  2552   2555   ){
  2553   2556     if( pExpr->eType==FTSQUERY_AND ){
  2554   2557       fts3ExprAssignCosts(pExpr->pLeft, ppExprCost);
  2555   2558       fts3ExprAssignCosts(pExpr->pRight, ppExprCost);
  2556   2559     }else{
  2557   2560       (*ppExprCost)->pExpr = pExpr;
  2558         -    (*ppExprCost)->nCost = fts3ExprCost(pExpr);;
         2561  +    (*ppExprCost)->nCost = fts3ExprCost(pExpr);
  2559   2562       (*ppExprCost)++;
  2560   2563     }
  2561   2564   }
  2562   2565   
  2563   2566   /*
  2564   2567   ** Evaluate the full-text expression pExpr against FTS3 table pTab. Store
  2565   2568   ** the resulting doclist in *paOut and *pnOut. This routine mallocs for
................................................................................
  2676   2679                 );
  2677   2680                 sqlite3_free(aNew);
  2678   2681               }
  2679   2682             }
  2680   2683           }
  2681   2684         }
  2682   2685   
  2683         -      *paOut = aRet;
  2684         -      *pnOut = nRet;
         2686  +      if( rc==SQLITE_OK ){
         2687  +        *paOut = aRet;
         2688  +        *pnOut = nRet;
         2689  +      }else{
         2690  +        assert( *paOut==0 );
         2691  +        sqlite3_free(aRet);
         2692  +      }
  2685   2693         sqlite3_free(aExpr);
  2686   2694         fts3ExprFreeSegReaders(pExpr);
  2687   2695   
  2688   2696       }else{
  2689   2697         char *aLeft;
  2690   2698         char *aRight;
  2691   2699         int nLeft;
................................................................................
  2750   2758             }
  2751   2759           }
  2752   2760         }
  2753   2761         sqlite3_free(aRight);
  2754   2762       }
  2755   2763     }
  2756   2764   
         2765  +  assert( rc==SQLITE_OK || *paOut==0 );
  2757   2766     return rc;
  2758   2767   }
  2759   2768   
  2760   2769   /*
  2761   2770   ** This function is called from within xNext() for each row visited by
  2762   2771   ** an FTS3 query. If evaluating the FTS3 query expression within xFilter()
  2763   2772   ** was able to determine the exact set of matching rows, this function sets
................................................................................
  3269   3278   */
  3270   3279   static void fts3MatchinfoFunc(
  3271   3280     sqlite3_context *pContext,      /* SQLite function call context */
  3272   3281     int nVal,                       /* Size of argument array */
  3273   3282     sqlite3_value **apVal           /* Array of arguments */
  3274   3283   ){
  3275   3284     Fts3Cursor *pCsr;               /* Cursor handle passed through apVal[0] */
  3276         -  assert( nVal==1 );
         3285  +  assert( nVal==1 || nVal==2 );
  3277   3286     if( SQLITE_OK==fts3FunctionArg(pContext, "matchinfo", apVal[0], &pCsr) ){
  3278         -    sqlite3Fts3Matchinfo(pContext, pCsr);
         3287  +    const char *zArg = 0;
         3288  +    if( nVal>1 ){
         3289  +      zArg = (const char *)sqlite3_value_text(apVal[1]);
         3290  +    }
         3291  +    sqlite3Fts3Matchinfo(pContext, pCsr, zArg);
  3279   3292     }
  3280   3293   }
  3281   3294   
  3282   3295   /*
  3283   3296   ** This routine implements the xFindFunction method for the FTS3
  3284   3297   ** virtual table.
  3285   3298   */
................................................................................
  3460   3473     ** module with sqlite.
  3461   3474     */
  3462   3475     if( SQLITE_OK==rc 
  3463   3476      && SQLITE_OK==(rc = sqlite3Fts3InitHashTable(db, pHash, "fts3_tokenizer"))
  3464   3477      && SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1))
  3465   3478      && SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", 1))
  3466   3479      && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 1))
         3480  +   && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 2))
  3467   3481      && SQLITE_OK==(rc = sqlite3_overload_function(db, "optimize", 1))
  3468   3482     ){
  3469   3483       rc = sqlite3_create_module_v2(
  3470   3484           db, "fts3", &fts3Module, (void *)pHash, hashDestroy
  3471   3485       );
  3472   3486       if( rc==SQLITE_OK ){
  3473   3487         rc = sqlite3_create_module_v2(

Changes to ext/fts3/fts3Int.h.

   158    158   struct Fts3Cursor {
   159    159     sqlite3_vtab_cursor base;       /* Base class used by SQLite core */
   160    160     i16 eSearch;                    /* Search strategy (see below) */
   161    161     u8 isEof;                       /* True if at End Of Results */
   162    162     u8 isRequireSeek;               /* True if must seek pStmt to %_content row */
   163    163     sqlite3_stmt *pStmt;            /* Prepared statement in use by the cursor */
   164    164     Fts3Expr *pExpr;                /* Parsed MATCH query string */
          165  +  int nPhrase;                    /* Number of matchable phrases in query */
   165    166     Fts3DeferredToken *pDeferred;   /* Deferred search tokens, if any */
   166    167     sqlite3_int64 iPrevId;          /* Previous id read from aDoclist */
   167    168     char *pNextId;                  /* Pointer into the body of aDoclist */
   168    169     char *aDoclist;                 /* List of docids for full-text queries */
   169    170     int nDoclist;                   /* Size of buffer at aDoclist */
   170         -  int isMatchinfoNeeded;          /* True when aMatchinfo[] needs filling in */
   171         -  u32 *aMatchinfo;                /* Information about most recent match */
   172    171     int eEvalmode;                  /* An FTS3_EVAL_XX constant */
   173    172     int nRowAvg;                    /* Average size of database rows, in pages */
          173  +
          174  +  int isMatchinfoNeeded;          /* True when aMatchinfo[] needs filling in */
          175  +  u32 *aMatchinfo;                /* Information about most recent match */
          176  +  int nMatchinfo;                 /* Number of elements in aMatchinfo[] */
          177  +  char *zMatchinfo;               /* Matchinfo specification */
   174    178   };
   175    179   
   176    180   #define FTS3_EVAL_FILTER    0
   177    181   #define FTS3_EVAL_NEXT      1
   178    182   #define FTS3_EVAL_MATCHINFO 2
   179    183   
   180    184   /*
................................................................................
   273    277   
   274    278   
   275    279   /* fts3_write.c */
   276    280   int sqlite3Fts3UpdateMethod(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*);
   277    281   int sqlite3Fts3PendingTermsFlush(Fts3Table *);
   278    282   void sqlite3Fts3PendingTermsClear(Fts3Table *);
   279    283   int sqlite3Fts3Optimize(Fts3Table *);
   280         -int sqlite3Fts3SegReaderNew(Fts3Table *,int, sqlite3_int64,
          284  +int sqlite3Fts3SegReaderNew(int, sqlite3_int64,
   281    285     sqlite3_int64, sqlite3_int64, const char *, int, Fts3SegReader**);
   282    286   int sqlite3Fts3SegReaderPending(Fts3Table*,const char*,int,int,Fts3SegReader**);
   283         -void sqlite3Fts3SegReaderFree(Fts3Table *, Fts3SegReader *);
          287  +void sqlite3Fts3SegReaderFree(Fts3SegReader *);
   284    288   int sqlite3Fts3SegReaderIterate(
   285    289     Fts3Table *, Fts3SegReader **, int, Fts3SegFilter *,
   286    290     int (*)(Fts3Table *, void *, char *, int, char *, int),  void *
   287    291   );
   288    292   int sqlite3Fts3SegReaderCost(Fts3Cursor *, Fts3SegReader *, int *);
   289    293   int sqlite3Fts3AllSegdirs(Fts3Table*, sqlite3_stmt **);
   290         -int sqlite3Fts3MatchinfoDocsizeLocal(Fts3Cursor*, u32*);
   291         -int sqlite3Fts3MatchinfoDocsizeGlobal(Fts3Cursor*, u32*);
   292    294   int sqlite3Fts3ReadLock(Fts3Table *);
   293    295   int sqlite3Fts3ReadBlock(Fts3Table*, sqlite3_int64, char **, int*);
   294    296   
          297  +int sqlite3Fts3SelectDoctotal(Fts3Table *, sqlite3_stmt **);
          298  +int sqlite3Fts3SelectDocsize(Fts3Table *, sqlite3_int64, sqlite3_stmt **);
          299  +
   295    300   void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *);
   296    301   int sqlite3Fts3DeferToken(Fts3Cursor *, Fts3PhraseToken *, int);
   297    302   int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *);
   298    303   void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *);
   299    304   char *sqlite3Fts3DeferredDoclist(Fts3DeferredToken *, int *);
   300    305   
   301    306   void sqlite3Fts3SegmentsClose(Fts3Table *);
................................................................................
   335    340   int sqlite3Fts3IsIdChar(char);
   336    341   
   337    342   /* fts3_snippet.c */
   338    343   void sqlite3Fts3Offsets(sqlite3_context*, Fts3Cursor*);
   339    344   void sqlite3Fts3Snippet(sqlite3_context *, Fts3Cursor *, const char *,
   340    345     const char *, const char *, int, int
   341    346   );
   342         -void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *);
          347  +void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *);
   343    348   
   344    349   /* fts3_expr.c */
   345    350   int sqlite3Fts3ExprParse(sqlite3_tokenizer *, 
   346    351     char **, int, int, const char *, int, Fts3Expr **
   347    352   );
   348    353   void sqlite3Fts3ExprFree(Fts3Expr *);
   349    354   #ifdef SQLITE_TEST
   350    355   int sqlite3Fts3ExprInitTestInterface(sqlite3 *db);
   351    356   #endif
   352    357   
   353    358   #endif /* _FTSINT_H */

Changes to ext/fts3/fts3_expr.c.

   401    401       }
   402    402     }
   403    403   
   404    404     /* Check for an open bracket. */
   405    405     if( sqlite3_fts3_enable_parentheses ){
   406    406       if( *zInput=='(' ){
   407    407         int nConsumed;
   408         -      int rc;
   409    408         pParse->nNest++;
   410    409         rc = fts3ExprParse(pParse, &zInput[1], nInput-1, ppExpr, &nConsumed);
   411    410         if( rc==SQLITE_OK && !*ppExpr ){
   412    411           rc = SQLITE_DONE;
   413    412         }
   414    413         *pnConsumed = (int)((zInput - z) + 1 + nConsumed);
   415    414         return rc;
................................................................................
   782    781       }
   783    782     }
   784    783   
   785    784     return sqlite3_finalize(pStmt);
   786    785   }
   787    786   
   788    787   /*
   789         -** This function is part of the test interface for the query parser. It
   790         -** writes a text representation of the query expression pExpr into the
   791         -** buffer pointed to by argument zBuf. It is assumed that zBuf is large 
   792         -** enough to store the required text representation.
          788  +** Return a pointer to a buffer containing a text representation of the
          789  +** expression passed as the first argument. The buffer is obtained from
          790  +** sqlite3_malloc(). It is the responsibility of the caller to use 
          791  +** sqlite3_free() to release the memory. If an OOM condition is encountered,
          792  +** NULL is returned.
          793  +**
          794  +** If the second argument is not NULL, then its contents are prepended to 
          795  +** the returned expression text and then freed using sqlite3_free().
   793    796   */
   794         -static void exprToString(Fts3Expr *pExpr, char *zBuf){
          797  +static char *exprToString(Fts3Expr *pExpr, char *zBuf){
   795    798     switch( pExpr->eType ){
   796    799       case FTSQUERY_PHRASE: {
   797    800         Fts3Phrase *pPhrase = pExpr->pPhrase;
   798    801         int i;
   799         -      zBuf += sprintf(zBuf, "PHRASE %d %d", pPhrase->iColumn, pPhrase->isNot);
   800         -      for(i=0; i<pPhrase->nToken; i++){
   801         -        zBuf += sprintf(zBuf," %.*s",pPhrase->aToken[i].n,pPhrase->aToken[i].z);
   802         -        zBuf += sprintf(zBuf,"%s", (pPhrase->aToken[i].isPrefix?"+":""));
          802  +      zBuf = sqlite3_mprintf(
          803  +          "%zPHRASE %d %d", zBuf, pPhrase->iColumn, pPhrase->isNot);
          804  +      for(i=0; zBuf && i<pPhrase->nToken; i++){
          805  +        zBuf = sqlite3_mprintf("%z %.*s%s", zBuf, 
          806  +            pPhrase->aToken[i].n, pPhrase->aToken[i].z,
          807  +            (pPhrase->aToken[i].isPrefix?"+":"")
          808  +        );
   803    809         }
   804         -      return;
          810  +      return zBuf;
   805    811       }
   806    812   
   807    813       case FTSQUERY_NEAR:
   808         -      zBuf += sprintf(zBuf, "NEAR/%d ", pExpr->nNear);
          814  +      zBuf = sqlite3_mprintf("%zNEAR/%d ", zBuf, pExpr->nNear);
   809    815         break;
   810    816       case FTSQUERY_NOT:
   811         -      zBuf += sprintf(zBuf, "NOT ");
          817  +      zBuf = sqlite3_mprintf("%zNOT ", zBuf);
   812    818         break;
   813    819       case FTSQUERY_AND:
   814         -      zBuf += sprintf(zBuf, "AND ");
          820  +      zBuf = sqlite3_mprintf("%zAND ", zBuf);
   815    821         break;
   816    822       case FTSQUERY_OR:
   817         -      zBuf += sprintf(zBuf, "OR ");
          823  +      zBuf = sqlite3_mprintf("%zOR ", zBuf);
   818    824         break;
   819    825     }
   820    826   
   821         -  zBuf += sprintf(zBuf, "{");
   822         -  exprToString(pExpr->pLeft, zBuf);
   823         -  zBuf += strlen(zBuf);
   824         -  zBuf += sprintf(zBuf, "} ");
          827  +  if( zBuf ) zBuf = sqlite3_mprintf("%z{", zBuf);
          828  +  if( zBuf ) zBuf = exprToString(pExpr->pLeft, zBuf);
          829  +  if( zBuf ) zBuf = sqlite3_mprintf("%z} {", zBuf);
          830  +
          831  +  if( zBuf ) zBuf = exprToString(pExpr->pRight, zBuf);
          832  +  if( zBuf ) zBuf = sqlite3_mprintf("%z}", zBuf);
   825    833   
   826         -  zBuf += sprintf(zBuf, "{");
   827         -  exprToString(pExpr->pRight, zBuf);
   828         -  zBuf += strlen(zBuf);
   829         -  zBuf += sprintf(zBuf, "}");
          834  +  return zBuf;
   830    835   }
   831    836   
   832    837   /*
   833    838   ** This is the implementation of a scalar SQL function used to test the 
   834    839   ** expression parser. It should be called as follows:
   835    840   **
   836    841   **   fts3_exprtest(<tokenizer>, <expr>, <column 1>, ...);
................................................................................
   853    858     int rc;
   854    859     char **azCol = 0;
   855    860     const char *zExpr;
   856    861     int nExpr;
   857    862     int nCol;
   858    863     int ii;
   859    864     Fts3Expr *pExpr;
          865  +  char *zBuf = 0;
   860    866     sqlite3 *db = sqlite3_context_db_handle(context);
   861    867   
   862    868     if( argc<3 ){
   863    869       sqlite3_result_error(context, 
   864    870           "Usage: fts3_exprtest(tokenizer, expr, col1, ...", -1
   865    871       );
   866    872       return;
................................................................................
   895    901     for(ii=0; ii<nCol; ii++){
   896    902       azCol[ii] = (char *)sqlite3_value_text(argv[ii+2]);
   897    903     }
   898    904   
   899    905     rc = sqlite3Fts3ExprParse(
   900    906         pTokenizer, azCol, nCol, nCol, zExpr, nExpr, &pExpr
   901    907     );
   902         -  if( rc==SQLITE_NOMEM ){
          908  +  if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){
          909  +    sqlite3_result_error(context, "Error parsing expression", -1);
          910  +  }else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){
   903    911       sqlite3_result_error_nomem(context);
   904         -    goto exprtest_out;
   905         -  }else if( rc==SQLITE_OK ){
   906         -    char zBuf[4096];
   907         -    exprToString(pExpr, zBuf);
          912  +  }else{
   908    913       sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
   909         -    sqlite3Fts3ExprFree(pExpr);
   910         -  }else{
   911         -    sqlite3_result_error(context, "Error parsing expression", -1);
          914  +    sqlite3_free(zBuf);
   912    915     }
          916  +
          917  +  sqlite3Fts3ExprFree(pExpr);
   913    918   
   914    919   exprtest_out:
   915    920     if( pModule && pTokenizer ){
   916    921       rc = pModule->xDestroy(pTokenizer);
   917    922     }
   918    923     sqlite3_free(azCol);
   919    924   }

Changes to ext/fts3/fts3_porter.c.

   339    339   ** Stemming never increases the length of the word.  So there is
   340    340   ** no chance of overflowing the zOut buffer.
   341    341   */
   342    342   static void porter_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){
   343    343     int i, j;
   344    344     char zReverse[28];
   345    345     char *z, *z2;
   346         -  if( nIn<3 || nIn>=sizeof(zReverse)-7 ){
          346  +  if( nIn<3 || nIn>=(int)sizeof(zReverse)-7 ){
   347    347       /* The word is too big or too small for the porter stemmer.
   348    348       ** Fallback to the copy stemmer */
   349    349       copy_stemmer(zIn, nIn, zOut, pnOut);
   350    350       return;
   351    351     }
   352    352     for(i=0, j=sizeof(zReverse)-6; i<nIn; i++, j--){
   353    353       char c = zIn[i];

Changes to ext/fts3/fts3_snippet.c.

    13     13   
    14     14   #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
    15     15   
    16     16   #include "fts3Int.h"
    17     17   #include <string.h>
    18     18   #include <assert.h>
    19     19   
           20  +/*
           21  +** Characters that may appear in the second argument to matchinfo().
           22  +*/
           23  +#define FTS3_MATCHINFO_NPHRASE   'p'        /* 1 value */
           24  +#define FTS3_MATCHINFO_NCOL      'c'        /* 1 value */
           25  +#define FTS3_MATCHINFO_NDOC      'n'        /* 1 value */
           26  +#define FTS3_MATCHINFO_AVGLENGTH 'a'        /* nCol values */
           27  +#define FTS3_MATCHINFO_LENGTH    'l'        /* nCol values */
           28  +#define FTS3_MATCHINFO_LCS       's'        /* nCol values */
           29  +#define FTS3_MATCHINFO_HITS      'x'        /* 3*nCol*nPhrase values */
           30  +
           31  +/*
           32  +** The default value for the second argument to matchinfo(). 
           33  +*/
           34  +#define FTS3_MATCHINFO_DEFAULT   "pcx"
           35  +
    20     36   
    21     37   /*
    22     38   ** Used as an fts3ExprIterate() context when loading phrase doclists to
    23     39   ** Fts3Expr.aDoclist[]/nDoclist.
    24     40   */
    25     41   typedef struct LoadDoclistCtx LoadDoclistCtx;
    26     42   struct LoadDoclistCtx {
................................................................................
    66     82   ** This type is used as an fts3ExprIterate() context object while 
    67     83   ** accumulating the data returned by the matchinfo() function.
    68     84   */
    69     85   typedef struct MatchInfo MatchInfo;
    70     86   struct MatchInfo {
    71     87     Fts3Cursor *pCursor;            /* FTS3 Cursor */
    72     88     int nCol;                       /* Number of columns in table */
           89  +  int nPhrase;                    /* Number of matchable phrases in query */
           90  +  sqlite3_int64 nDoc;             /* Number of docs in database */
    73     91     u32 *aMatchinfo;                /* Pre-allocated buffer */
    74     92   };
    75     93   
    76     94   
    77     95   
    78     96   /*
    79     97   ** The snippet() and offsets() functions both return text values. An instance
................................................................................
   266    284     if( rc==SQLITE_OK ){
   267    285       (void)fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb2, 0);
   268    286     }
   269    287     if( pnPhrase ) *pnPhrase = sCtx.nPhrase;
   270    288     if( pnToken ) *pnToken = sCtx.nToken;
   271    289     return rc;
   272    290   }
          291  +
          292  +static int fts3ExprPhraseCountCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
          293  +  (*(int *)ctx)++;
          294  +  UNUSED_PARAMETER(pExpr);
          295  +  UNUSED_PARAMETER(iPhrase);
          296  +  return SQLITE_OK;
          297  +}
          298  +static int fts3ExprPhraseCount(Fts3Expr *pExpr){
          299  +  int nPhrase = 0;
          300  +  (void)fts3ExprIterate(pExpr, fts3ExprPhraseCountCb, (void *)&nPhrase);
          301  +  return nPhrase;
          302  +}
   273    303   
   274    304   /*
   275    305   ** Advance the position list iterator specified by the first two 
   276    306   ** arguments so that it points to the first element with a value greater
   277    307   ** than or equal to parameter iNext.
   278    308   */
   279    309   static void fts3SnippetAdvance(char **ppIter, int *piIter, int iNext){
................................................................................
   779    809     }
   780    810     pCsr++;
   781    811     *pp = pCsr;
   782    812   }
   783    813   
   784    814   /*
   785    815   ** fts3ExprIterate() callback used to collect the "global" matchinfo stats
   786         -** for a single query. The "global" stats are those elements of the matchinfo
   787         -** array that are constant for all rows returned by the current query.
          816  +** for a single query. 
          817  +**
          818  +** fts3ExprIterate() callback to load the 'global' elements of a
          819  +** FTS3_MATCHINFO_HITS matchinfo array. The global stats are those elements 
          820  +** of the matchinfo array that are constant for all rows returned by the 
          821  +** current query.
          822  +**
          823  +** Argument pCtx is actually a pointer to a struct of type MatchInfo. This
          824  +** function populates Matchinfo.aMatchinfo[] as follows:
          825  +**
          826  +**   for(iCol=0; iCol<nCol; iCol++){
          827  +**     aMatchinfo[3*iPhrase*nCol + 3*iCol + 1] = X;
          828  +**     aMatchinfo[3*iPhrase*nCol + 3*iCol + 2] = Y;
          829  +**   }
          830  +**
          831  +** where X is the number of matches for phrase iPhrase is column iCol of all
          832  +** rows of the table. Y is the number of rows for which column iCol contains
          833  +** at least one instance of phrase iPhrase.
          834  +**
          835  +** If the phrase pExpr consists entirely of deferred tokens, then all X and
          836  +** Y values are set to nDoc, where nDoc is the number of documents in the 
          837  +** file system. This is done because the full-text index doclist is required
          838  +** to calculate these values properly, and the full-text index doclist is
          839  +** not available for deferred tokens.
   788    840   */
   789         -static int fts3ExprGlobalMatchinfoCb(
          841  +static int fts3ExprGlobalHitsCb(
   790    842     Fts3Expr *pExpr,                /* Phrase expression node */
   791    843     int iPhrase,                    /* Phrase number (numbered from zero) */
   792    844     void *pCtx                      /* Pointer to MatchInfo structure */
   793    845   ){
   794    846     MatchInfo *p = (MatchInfo *)pCtx;
   795    847     Fts3Cursor *pCsr = p->pCursor;
   796    848     char *pIter;
   797    849     char *pEnd;
   798    850     char *pFree = 0;
   799         -  const int iStart = 2 + (iPhrase * p->nCol * 3) + 1;
          851  +  u32 *aOut = &p->aMatchinfo[3*iPhrase*p->nCol];
   800    852   
   801    853     assert( pExpr->isLoaded );
   802    854     assert( pExpr->eType==FTSQUERY_PHRASE );
   803    855   
   804    856     if( pCsr->pDeferred ){
   805    857       Fts3Phrase *pPhrase = pExpr->pPhrase;
   806    858       int ii;
................................................................................
   810    862       if( ii<pPhrase->nToken ){
   811    863         int nFree = 0;
   812    864         int rc = sqlite3Fts3ExprLoadFtDoclist(pCsr, pExpr, &pFree, &nFree);
   813    865         if( rc!=SQLITE_OK ) return rc;
   814    866         pIter = pFree;
   815    867         pEnd = &pFree[nFree];
   816    868       }else{
   817         -      int nDoc = p->aMatchinfo[2 + 3*p->nCol*p->aMatchinfo[0]];
   818         -      for(ii=0; ii<p->nCol; ii++){
   819         -        p->aMatchinfo[iStart + ii*3] = nDoc;
   820         -        p->aMatchinfo[iStart + ii*3 + 1] = nDoc;
          869  +      int iCol;                   /* Column index */
          870  +      for(iCol=0; iCol<p->nCol; iCol++){
          871  +        aOut[iCol*3 + 1] = (u32)p->nDoc;
          872  +        aOut[iCol*3 + 2] = (u32)p->nDoc;
   821    873         }
   822    874         return SQLITE_OK;
   823    875       }
   824    876     }else{
   825    877       pIter = pExpr->aDoclist;
   826    878       pEnd = &pExpr->aDoclist[pExpr->nDoclist];
   827    879     }
   828    880   
   829    881     /* Fill in the global hit count matrix row for this phrase. */
   830    882     while( pIter<pEnd ){
   831    883       while( *pIter++ & 0x80 );      /* Skip past docid. */
   832         -    fts3LoadColumnlistCounts(&pIter, &p->aMatchinfo[iStart], 1);
          884  +    fts3LoadColumnlistCounts(&pIter, &aOut[1], 1);
   833    885     }
   834    886   
   835    887     sqlite3_free(pFree);
   836    888     return SQLITE_OK;
   837    889   }
   838    890   
   839    891   /*
   840         -** fts3ExprIterate() callback used to collect the "local" matchinfo stats
   841         -** for a single query. The "local" stats are those elements of the matchinfo
          892  +** fts3ExprIterate() callback used to collect the "local" part of the
          893  +** FTS3_MATCHINFO_HITS array. The local stats are those elements of the 
   842    894   ** array that are different for each row returned by the query.
   843    895   */
   844         -static int fts3ExprLocalMatchinfoCb(
          896  +static int fts3ExprLocalHitsCb(
   845    897     Fts3Expr *pExpr,                /* Phrase expression node */
   846    898     int iPhrase,                    /* Phrase number */
   847    899     void *pCtx                      /* Pointer to MatchInfo structure */
   848    900   ){
   849    901     MatchInfo *p = (MatchInfo *)pCtx;
   850    902   
   851    903     if( pExpr->aDoclist ){
   852    904       char *pCsr;
   853         -    int iStart = 2 + (iPhrase * p->nCol * 3);
          905  +    int iStart = iPhrase * p->nCol * 3;
   854    906       int i;
   855    907   
   856    908       for(i=0; i<p->nCol; i++) p->aMatchinfo[iStart+i*3] = 0;
   857    909   
   858    910       pCsr = sqlite3Fts3FindPositions(pExpr, p->pCursor->iPrevId, -1);
   859    911       if( pCsr ){
   860    912         fts3LoadColumnlistCounts(&pCsr, &p->aMatchinfo[iStart], 0);
   861    913       }
   862    914     }
   863    915   
   864    916     return SQLITE_OK;
   865    917   }
          918  +
          919  +static int fts3MatchinfoCheck(
          920  +  Fts3Table *pTab, 
          921  +  char cArg,
          922  +  char **pzErr
          923  +){
          924  +  if( (cArg==FTS3_MATCHINFO_NPHRASE)
          925  +   || (cArg==FTS3_MATCHINFO_NCOL)
          926  +   || (cArg==FTS3_MATCHINFO_NDOC && pTab->bHasStat)
          927  +   || (cArg==FTS3_MATCHINFO_AVGLENGTH && pTab->bHasStat)
          928  +   || (cArg==FTS3_MATCHINFO_LENGTH && pTab->bHasDocsize)
          929  +   || (cArg==FTS3_MATCHINFO_LCS)
          930  +   || (cArg==FTS3_MATCHINFO_HITS)
          931  +  ){
          932  +    return SQLITE_OK;
          933  +  }
          934  +  *pzErr = sqlite3_mprintf("unrecognized matchinfo request: %c", cArg);
          935  +  return SQLITE_ERROR;
          936  +}
          937  +
          938  +static int fts3MatchinfoSize(MatchInfo *pInfo, char cArg){
          939  +  int nVal;                       /* Number of integers output by cArg */
          940  +
          941  +  switch( cArg ){
          942  +    case FTS3_MATCHINFO_NDOC:
          943  +    case FTS3_MATCHINFO_NPHRASE: 
          944  +    case FTS3_MATCHINFO_NCOL: 
          945  +      nVal = 1;
          946  +      break;
          947  +
          948  +    case FTS3_MATCHINFO_AVGLENGTH:
          949  +    case FTS3_MATCHINFO_LENGTH:
          950  +    case FTS3_MATCHINFO_LCS:
          951  +      nVal = pInfo->nCol;
          952  +      break;
          953  +
          954  +    default:
          955  +      assert( cArg==FTS3_MATCHINFO_HITS );
          956  +      nVal = pInfo->nCol * pInfo->nPhrase * 3;
          957  +      break;
          958  +  }
          959  +
          960  +  return nVal;
          961  +}
          962  +
          963  +static int fts3MatchinfoSelectDoctotal(
          964  +  Fts3Table *pTab,
          965  +  sqlite3_stmt **ppStmt,
          966  +  sqlite3_int64 *pnDoc,
          967  +  const char **paLen
          968  +){
          969  +  sqlite3_stmt *pStmt;
          970  +  const char *a;
          971  +  sqlite3_int64 nDoc;
          972  +
          973  +  if( !*ppStmt ){
          974  +    int rc = sqlite3Fts3SelectDoctotal(pTab, ppStmt);
          975  +    if( rc!=SQLITE_OK ) return rc;
          976  +  }
          977  +  pStmt = *ppStmt;
          978  +
          979  +  a = sqlite3_column_blob(pStmt, 0);
          980  +  a += sqlite3Fts3GetVarint(a, &nDoc);
          981  +  *pnDoc = (u32)nDoc;
          982  +
          983  +  if( paLen ) *paLen = a;
          984  +  return SQLITE_OK;
          985  +}
          986  +
          987  +/*
          988  +** An instance of the following structure is used to store state while 
          989  +** iterating through a multi-column position-list corresponding to the
          990  +** hits for a single phrase on a single row in order to calculate the
          991  +** values for a matchinfo() FTS3_MATCHINFO_LCS request.
          992  +*/
          993  +typedef struct LcsIterator LcsIterator;
          994  +struct LcsIterator {
          995  +  Fts3Expr *pExpr;                /* Pointer to phrase expression */
          996  +  char *pRead;                    /* Cursor used to iterate through aDoclist */
          997  +  int iPosOffset;                 /* Tokens count up to end of this phrase */
          998  +  int iCol;                       /* Current column number */
          999  +  int iPos;                       /* Current position */
         1000  +};
         1001  +
         1002  +/* 
         1003  +** If LcsIterator.iCol is set to the following value, the iterator has
         1004  +** finished iterating through all offsets for all columns.
         1005  +*/
         1006  +#define LCS_ITERATOR_FINISHED 0x7FFFFFFF;
         1007  +
         1008  +static int fts3MatchinfoLcsCb(
         1009  +  Fts3Expr *pExpr,                /* Phrase expression node */
         1010  +  int iPhrase,                    /* Phrase number (numbered from zero) */
         1011  +  void *pCtx                      /* Pointer to MatchInfo structure */
         1012  +){
         1013  +  LcsIterator *aIter = (LcsIterator *)pCtx;
         1014  +  aIter[iPhrase].pExpr = pExpr;
         1015  +  return SQLITE_OK;
         1016  +}
         1017  +
         1018  +/*
         1019  +** Advance the iterator passed as an argument to the next position. Return
         1020  +** 1 if the iterator is at EOF or if it now points to the start of the
         1021  +** position list for the next column.
         1022  +*/
         1023  +static int fts3LcsIteratorAdvance(LcsIterator *pIter){
         1024  +  char *pRead = pIter->pRead;
         1025  +  sqlite3_int64 iRead;
         1026  +  int rc = 0;
         1027  +
         1028  +  pRead += sqlite3Fts3GetVarint(pRead, &iRead);
         1029  +  if( iRead==0 ){
         1030  +    pIter->iCol = LCS_ITERATOR_FINISHED;
         1031  +    rc = 1;
         1032  +  }else{
         1033  +    if( iRead==1 ){
         1034  +      pRead += sqlite3Fts3GetVarint(pRead, &iRead);
         1035  +      pIter->iCol = (int)iRead;
         1036  +      pIter->iPos = pIter->iPosOffset;
         1037  +      pRead += sqlite3Fts3GetVarint(pRead, &iRead);
         1038  +      rc = 1;
         1039  +    }
         1040  +    pIter->iPos += (int)(iRead-2);
         1041  +  }
         1042  +
         1043  +  pIter->pRead = pRead;
         1044  +  return rc;
         1045  +}
         1046  +  
         1047  +/*
         1048  +** This function implements the FTS3_MATCHINFO_LCS matchinfo() flag. 
         1049  +**
         1050  +** If the call is successful, the longest-common-substring lengths for each
         1051  +** column are written into the first nCol elements of the pInfo->aMatchinfo[] 
         1052  +** array before returning. SQLITE_OK is returned in this case.
         1053  +**
         1054  +** Otherwise, if an error occurs, an SQLite error code is returned and the
         1055  +** data written to the first nCol elements of pInfo->aMatchinfo[] is 
         1056  +** undefined.
         1057  +*/
         1058  +static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
         1059  +  LcsIterator *aIter;
         1060  +  int i;
         1061  +  int iCol;
         1062  +  int nToken = 0;
         1063  +
         1064  +  /* Allocate and populate the array of LcsIterator objects. The array
         1065  +  ** contains one element for each matchable phrase in the query.
         1066  +  **/
         1067  +  aIter = sqlite3_malloc(sizeof(LcsIterator) * pCsr->nPhrase);
         1068  +  if( !aIter ) return SQLITE_NOMEM;
         1069  +  memset(aIter, 0, sizeof(LcsIterator) * pCsr->nPhrase);
         1070  +  (void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter);
         1071  +  for(i=0; i<pInfo->nPhrase; i++){
         1072  +    LcsIterator *pIter = &aIter[i];
         1073  +    nToken -= pIter->pExpr->pPhrase->nToken;
         1074  +    pIter->iPosOffset = nToken;
         1075  +    pIter->pRead = sqlite3Fts3FindPositions(pIter->pExpr, pCsr->iPrevId, -1);
         1076  +    if( pIter->pRead ){
         1077  +      pIter->iPos = pIter->iPosOffset;
         1078  +      fts3LcsIteratorAdvance(&aIter[i]);
         1079  +    }else{
         1080  +      pIter->iCol = LCS_ITERATOR_FINISHED;
         1081  +    }
         1082  +  }
         1083  +
         1084  +  for(iCol=0; iCol<pInfo->nCol; iCol++){
         1085  +    int nLcs = 0;                 /* LCS value for this column */
         1086  +    int nLive = 0;                /* Number of iterators in aIter not at EOF */
         1087  +
         1088  +    /* Loop through the iterators in aIter[]. Set nLive to the number of
         1089  +    ** iterators that point to a position-list corresponding to column iCol.
         1090  +    */
         1091  +    for(i=0; i<pInfo->nPhrase; i++){
         1092  +      assert( aIter[i].iCol>=iCol );
         1093  +      if( aIter[i].iCol==iCol ) nLive++;
         1094  +    }
         1095  +
         1096  +    /* The following loop runs until all iterators in aIter[] have finished
         1097  +    ** iterating through positions in column iCol. Exactly one of the 
         1098  +    ** iterators is advanced each time the body of the loop is run.
         1099  +    */
         1100  +    while( nLive>0 ){
         1101  +      LcsIterator *pAdv = 0;      /* The iterator to advance by one position */
         1102  +      int nThisLcs = 0;           /* LCS for the current iterator positions */
         1103  +
         1104  +      for(i=0; i<pInfo->nPhrase; i++){
         1105  +        LcsIterator *pIter = &aIter[i];
         1106  +        if( iCol!=pIter->iCol ){  
         1107  +          /* This iterator is already at EOF for this column. */
         1108  +          nThisLcs = 0;
         1109  +        }else{
         1110  +          if( pAdv==0 || pIter->iPos<pAdv->iPos ){
         1111  +            pAdv = pIter;
         1112  +          }
         1113  +          if( nThisLcs==0 || pIter->iPos==pIter[-1].iPos ){
         1114  +            nThisLcs++;
         1115  +          }else{
         1116  +            nThisLcs = 1;
         1117  +          }
         1118  +          if( nThisLcs>nLcs ) nLcs = nThisLcs;
         1119  +        }
         1120  +      }
         1121  +      if( fts3LcsIteratorAdvance(pAdv) ) nLive--;
         1122  +    }
         1123  +
         1124  +    pInfo->aMatchinfo[iCol] = nLcs;
         1125  +  }
         1126  +
         1127  +  sqlite3_free(aIter);
         1128  +  return SQLITE_OK;
         1129  +}
         1130  +
         1131  +/*
         1132  +** Populate the buffer pInfo->aMatchinfo[] with an array of integers to
         1133  +** be returned by the matchinfo() function. Argument zArg contains the 
         1134  +** format string passed as the second argument to matchinfo (or the
         1135  +** default value "pcx" if no second argument was specified). The format
         1136  +** string has already been validated and the pInfo->aMatchinfo[] array
         1137  +** is guaranteed to be large enough for the output.
         1138  +**
         1139  +** If bGlobal is true, then populate all fields of the matchinfo() output.
         1140  +** If it is false, then assume that those fields that do not change between
         1141  +** rows (i.e. FTS3_MATCHINFO_NPHRASE, NCOL, NDOC, AVGLENGTH and part of HITS)
         1142  +** have already been populated.
         1143  +**
         1144  +** Return SQLITE_OK if successful, or an SQLite error code if an error 
         1145  +** occurs. If a value other than SQLITE_OK is returned, the state the
         1146  +** pInfo->aMatchinfo[] buffer is left in is undefined.
         1147  +*/
         1148  +static int fts3MatchinfoValues(
         1149  +  Fts3Cursor *pCsr,               /* FTS3 cursor object */
         1150  +  int bGlobal,                    /* True to grab the global stats */
         1151  +  MatchInfo *pInfo,               /* Matchinfo context object */
         1152  +  const char *zArg                /* Matchinfo format string */
         1153  +){
         1154  +  int rc = SQLITE_OK;
         1155  +  int i;
         1156  +  Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
         1157  +  sqlite3_stmt *pSelect = 0;
         1158  +
         1159  +  for(i=0; rc==SQLITE_OK && zArg[i]; i++){
         1160  +
         1161  +    switch( zArg[i] ){
         1162  +      case FTS3_MATCHINFO_NPHRASE:
         1163  +        if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nPhrase;
         1164  +        break;
         1165  +
         1166  +      case FTS3_MATCHINFO_NCOL:
         1167  +        if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nCol;
         1168  +        break;
         1169  +        
         1170  +      case FTS3_MATCHINFO_NDOC:
         1171  +        if( bGlobal ){
         1172  +          sqlite3_int64 nDoc;
         1173  +          rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, 0);
         1174  +          pInfo->aMatchinfo[0] = (u32)nDoc;
         1175  +        }
         1176  +        break;
         1177  +
         1178  +      case FTS3_MATCHINFO_AVGLENGTH: 
         1179  +        if( bGlobal ){
         1180  +          sqlite3_int64 nDoc;     /* Number of rows in table */
         1181  +          const char *a;          /* Aggregate column length array */
         1182  +
         1183  +          rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, &a);
         1184  +          if( rc==SQLITE_OK ){
         1185  +            int iCol;
         1186  +            for(iCol=0; iCol<pInfo->nCol; iCol++){
         1187  +              sqlite3_int64 nToken;
         1188  +              a += sqlite3Fts3GetVarint(a, &nToken);
         1189  +              pInfo->aMatchinfo[iCol] = (u32)(((u32)(nToken&0xffffffff)+nDoc/2)/nDoc);
         1190  +            }
         1191  +          }
         1192  +        }
         1193  +        break;
         1194  +
         1195  +      case FTS3_MATCHINFO_LENGTH: {
         1196  +        sqlite3_stmt *pSelectDocsize = 0;
         1197  +        rc = sqlite3Fts3SelectDocsize(pTab, pCsr->iPrevId, &pSelectDocsize);
         1198  +        if( rc==SQLITE_OK ){
         1199  +          int iCol;
         1200  +          const char *a = sqlite3_column_blob(pSelectDocsize, 0);
         1201  +          for(iCol=0; iCol<pInfo->nCol; iCol++){
         1202  +            sqlite3_int64 nToken;
         1203  +            a += sqlite3Fts3GetVarint(a, &nToken);
         1204  +            pInfo->aMatchinfo[iCol] = (u32)nToken;
         1205  +          }
         1206  +        }
         1207  +        sqlite3_reset(pSelectDocsize);
         1208  +        break;
         1209  +      }
         1210  +
         1211  +      case FTS3_MATCHINFO_LCS:
         1212  +        rc = fts3ExprLoadDoclists(pCsr, 0, 0);
         1213  +        if( rc==SQLITE_OK ){
         1214  +          rc = fts3MatchinfoLcs(pCsr, pInfo);
         1215  +        }
         1216  +        break;
         1217  +
         1218  +      default: {
         1219  +        Fts3Expr *pExpr;
         1220  +        assert( zArg[i]==FTS3_MATCHINFO_HITS );
         1221  +        pExpr = pCsr->pExpr;
         1222  +        rc = fts3ExprLoadDoclists(pCsr, 0, 0);
         1223  +        if( rc!=SQLITE_OK ) break;
         1224  +        if( bGlobal ){
         1225  +          if( pCsr->pDeferred ){
         1226  +            rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &pInfo->nDoc, 0);
         1227  +            if( rc!=SQLITE_OK ) break;
         1228  +          }
         1229  +          rc = fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo);
         1230  +          if( rc!=SQLITE_OK ) break;
         1231  +        }
         1232  +        (void)fts3ExprIterate(pExpr, fts3ExprLocalHitsCb,(void*)pInfo);
         1233  +        break;
         1234  +      }
         1235  +    }
         1236  +
         1237  +    pInfo->aMatchinfo += fts3MatchinfoSize(pInfo, zArg[i]);
         1238  +  }
         1239  +
         1240  +  sqlite3_reset(pSelect);
         1241  +  return rc;
         1242  +}
         1243  +
   866   1244   
   867   1245   /*
   868   1246   ** Populate pCsr->aMatchinfo[] with data for the current row. The 
   869   1247   ** 'matchinfo' data is an array of 32-bit unsigned integers (C type u32).
   870   1248   */
   871         -static int fts3GetMatchinfo(Fts3Cursor *pCsr){
         1249  +static int fts3GetMatchinfo(
         1250  +  Fts3Cursor *pCsr,               /* FTS3 Cursor object */
         1251  +  const char *zArg                /* Second argument to matchinfo() function */
         1252  +){
   872   1253     MatchInfo sInfo;
   873   1254     Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
   874   1255     int rc = SQLITE_OK;
         1256  +  int bGlobal = 0;                /* Collect 'global' stats as well as local */
   875   1257   
         1258  +  memset(&sInfo, 0, sizeof(MatchInfo));
   876   1259     sInfo.pCursor = pCsr;
   877   1260     sInfo.nCol = pTab->nColumn;
   878   1261   
         1262  +  /* If there is cached matchinfo() data, but the format string for the 
         1263  +  ** cache does not match the format string for this request, discard 
         1264  +  ** the cached data. */
         1265  +  if( pCsr->zMatchinfo && strcmp(pCsr->zMatchinfo, zArg) ){
         1266  +    assert( pCsr->aMatchinfo );
         1267  +    sqlite3_free(pCsr->aMatchinfo);
         1268  +    pCsr->zMatchinfo = 0;
         1269  +    pCsr->aMatchinfo = 0;
         1270  +  }
         1271  +
         1272  +  /* If Fts3Cursor.aMatchinfo[] is NULL, then this is the first time the
         1273  +  ** matchinfo function has been called for this query. In this case 
         1274  +  ** allocate the array used to accumulate the matchinfo data and
         1275  +  ** initialize those elements that are constant for every row.
         1276  +  */
   879   1277     if( pCsr->aMatchinfo==0 ){
   880         -    /* If Fts3Cursor.aMatchinfo[] is NULL, then this is the first time the
   881         -    ** matchinfo function has been called for this query. In this case 
   882         -    ** allocate the array used to accumulate the matchinfo data and
   883         -    ** initialize those elements that are constant for every row.
   884         -    */
   885         -    int nPhrase;                  /* Number of phrases */
   886         -    int nMatchinfo;               /* Number of u32 elements in match-info */
         1278  +    int nMatchinfo = 0;           /* Number of u32 elements in match-info */
         1279  +    int nArg;                     /* Bytes in zArg */
         1280  +    int i;                        /* Used to iterate through zArg */
   887   1281   
   888         -    /* Load doclists for each phrase in the query. */
   889         -    rc = fts3ExprLoadDoclists(pCsr, &nPhrase, 0);
   890         -    if( rc!=SQLITE_OK ){
   891         -      return rc;
   892         -    }
   893         -    nMatchinfo = 2 + 3*sInfo.nCol*nPhrase;
   894         -    if( pTab->bHasDocsize ){
   895         -      nMatchinfo += 1 + 2*pTab->nColumn;
         1282  +    /* Determine the number of phrases in the query */
         1283  +    pCsr->nPhrase = fts3ExprPhraseCount(pCsr->pExpr);
         1284  +    sInfo.nPhrase = pCsr->nPhrase;
         1285  +
         1286  +    /* Determine the number of integers in the buffer returned by this call. */
         1287  +    for(i=0; zArg[i]; i++){
         1288  +      nMatchinfo += fts3MatchinfoSize(&sInfo, zArg[i]);
   896   1289       }
   897   1290   
   898         -    sInfo.aMatchinfo = (u32 *)sqlite3_malloc(sizeof(u32)*nMatchinfo);
   899         -    if( !sInfo.aMatchinfo ){ 
   900         -      return SQLITE_NOMEM;
   901         -    }
   902         -    memset(sInfo.aMatchinfo, 0, sizeof(u32)*nMatchinfo);
         1291  +    /* Allocate space for Fts3Cursor.aMatchinfo[] and Fts3Cursor.zMatchinfo. */
         1292  +    nArg = (int)strlen(zArg);
         1293  +    pCsr->aMatchinfo = (u32 *)sqlite3_malloc(sizeof(u32)*nMatchinfo + nArg + 1);
         1294  +    if( !pCsr->aMatchinfo ) return SQLITE_NOMEM;
   903   1295   
   904         -    /* First element of match-info is the number of phrases in the query */
   905         -    sInfo.aMatchinfo[0] = nPhrase;
   906         -    sInfo.aMatchinfo[1] = sInfo.nCol;
   907         -    if( pTab->bHasDocsize ){
   908         -      int ofst = 2 + 3*sInfo.aMatchinfo[0]*sInfo.aMatchinfo[1];
   909         -      rc = sqlite3Fts3MatchinfoDocsizeGlobal(pCsr, &sInfo.aMatchinfo[ofst]);
   910         -    }
   911         -    (void)fts3ExprIterate(pCsr->pExpr, fts3ExprGlobalMatchinfoCb,(void*)&sInfo);
   912         -    pCsr->aMatchinfo = sInfo.aMatchinfo;
         1296  +    pCsr->zMatchinfo = (char *)&pCsr->aMatchinfo[nMatchinfo];
         1297  +    pCsr->nMatchinfo = nMatchinfo;
         1298  +    memcpy(pCsr->zMatchinfo, zArg, nArg+1);
         1299  +    memset(pCsr->aMatchinfo, 0, sizeof(u32)*nMatchinfo);
   913   1300       pCsr->isMatchinfoNeeded = 1;
         1301  +    bGlobal = 1;
   914   1302     }
   915   1303   
   916   1304     sInfo.aMatchinfo = pCsr->aMatchinfo;
   917         -  if( rc==SQLITE_OK && pCsr->isMatchinfoNeeded ){
   918         -    (void)fts3ExprIterate(pCsr->pExpr, fts3ExprLocalMatchinfoCb, (void*)&sInfo);
   919         -    if( pTab->bHasDocsize ){
   920         -      int ofst = 2 + 3*sInfo.aMatchinfo[0]*sInfo.aMatchinfo[1];
   921         -      rc = sqlite3Fts3MatchinfoDocsizeLocal(pCsr, &sInfo.aMatchinfo[ofst]);
   922         -    }
         1305  +  sInfo.nPhrase = pCsr->nPhrase;
         1306  +  if( pCsr->isMatchinfoNeeded ){
         1307  +    rc = fts3MatchinfoValues(pCsr, bGlobal, &sInfo, zArg);
   923   1308       pCsr->isMatchinfoNeeded = 0;
   924   1309     }
   925   1310   
   926         -  return SQLITE_OK;
         1311  +  return rc;
   927   1312   }
   928   1313   
   929   1314   /*
   930   1315   ** Implementation of snippet() function.
   931   1316   */
   932   1317   void sqlite3Fts3Snippet(
   933   1318     sqlite3_context *pCtx,          /* SQLite function call context */
................................................................................
   980   1365         memset(pFragment, 0, sizeof(*pFragment));
   981   1366   
   982   1367         /* Loop through all columns of the table being considered for snippets.
   983   1368         ** If the iCol argument to this function was negative, this means all
   984   1369         ** columns of the FTS3 table. Otherwise, only column iCol is considered.
   985   1370         */
   986   1371         for(iRead=0; iRead<pTab->nColumn; iRead++){
   987         -        SnippetFragment sF;
         1372  +        SnippetFragment sF = {0, 0, 0, 0};
   988   1373           int iS;
   989   1374           if( iCol>=0 && iRead!=iCol ) continue;
   990   1375   
   991   1376           /* Find the best snippet of nFToken tokens in column iRead. */
   992   1377           rc = fts3BestSnippet(nFToken, pCsr, iRead, mCovered, &mSeen, &sF, &iS);
   993   1378           if( rc!=SQLITE_OK ){
   994   1379             goto snippet_out;
................................................................................
  1207   1592     }
  1208   1593     return;
  1209   1594   }
  1210   1595   
  1211   1596   /*
  1212   1597   ** Implementation of matchinfo() function.
  1213   1598   */
  1214         -void sqlite3Fts3Matchinfo(sqlite3_context *pContext, Fts3Cursor *pCsr){
         1599  +void sqlite3Fts3Matchinfo(
         1600  +  sqlite3_context *pContext,      /* Function call context */
         1601  +  Fts3Cursor *pCsr,               /* FTS3 table cursor */
         1602  +  const char *zArg                /* Second arg to matchinfo() function */
         1603  +){
         1604  +  Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
  1215   1605     int rc;
         1606  +  int i;
         1607  +  const char *zFormat;
         1608  +
         1609  +  if( zArg ){
         1610  +    for(i=0; zArg[i]; i++){
         1611  +      char *zErr = 0;
         1612  +      if( fts3MatchinfoCheck(pTab, zArg[i], &zErr) ){
         1613  +        sqlite3_result_error(pContext, zErr, -1);
         1614  +        sqlite3_free(zErr);
         1615  +        return;
         1616  +      }
         1617  +    }
         1618  +    zFormat = zArg;
         1619  +  }else{
         1620  +    zFormat = FTS3_MATCHINFO_DEFAULT;
         1621  +  }
         1622  +
  1216   1623     if( !pCsr->pExpr ){
  1217   1624       sqlite3_result_blob(pContext, "", 0, SQLITE_STATIC);
  1218   1625       return;
  1219   1626     }
  1220         -  rc = fts3GetMatchinfo(pCsr);
  1221         -  sqlite3Fts3SegmentsClose((Fts3Table *)pCsr->base.pVtab );
         1627  +
         1628  +  /* Retrieve matchinfo() data. */
         1629  +  rc = fts3GetMatchinfo(pCsr, zFormat);
         1630  +  sqlite3Fts3SegmentsClose(pTab);
         1631  +
  1222   1632     if( rc!=SQLITE_OK ){
  1223   1633       sqlite3_result_error_code(pContext, rc);
  1224   1634     }else{
  1225         -    Fts3Table *pTab = (Fts3Table*)pCsr->base.pVtab;
  1226         -    int n = sizeof(u32)*(2+pCsr->aMatchinfo[0]*pCsr->aMatchinfo[1]*3);
  1227         -    if( pTab->bHasDocsize ){
  1228         -      n += sizeof(u32)*(1 + 2*pTab->nColumn);
  1229         -    }
         1635  +    int n = pCsr->nMatchinfo * sizeof(u32);
  1230   1636       sqlite3_result_blob(pContext, pCsr->aMatchinfo, n, SQLITE_TRANSIENT);
  1231   1637     }
  1232   1638   }
  1233   1639   
  1234   1640   #endif

Changes to ext/fts3/fts3_tokenizer.c.

   461    461     zTest = sqlite3_mprintf("%s_test", zName);
   462    462     zTest2 = sqlite3_mprintf("%s_internal_test", zName);
   463    463     if( !zTest || !zTest2 ){
   464    464       rc = SQLITE_NOMEM;
   465    465     }
   466    466   #endif
   467    467   
   468         -  if( SQLITE_OK!=rc
   469         -   || SQLITE_OK!=(rc = sqlite3_create_function(db, zName, 1, any, p, scalarFunc, 0, 0))
   470         -   || SQLITE_OK!=(rc = sqlite3_create_function(db, zName, 2, any, p, scalarFunc, 0, 0))
          468  +  if( SQLITE_OK==rc ){
          469  +    rc = sqlite3_create_function(db, zName, 1, any, p, scalarFunc, 0, 0);
          470  +  }
          471  +  if( SQLITE_OK==rc ){
          472  +    rc = sqlite3_create_function(db, zName, 2, any, p, scalarFunc, 0, 0);
          473  +  }
   471    474   #ifdef SQLITE_TEST
   472         -   || SQLITE_OK!=(rc = sqlite3_create_function(db, zTest, 2, any, p, testFunc, 0, 0))
   473         -   || SQLITE_OK!=(rc = sqlite3_create_function(db, zTest, 3, any, p, testFunc, 0, 0))
   474         -   || SQLITE_OK!=(rc = sqlite3_create_function(db, zTest2, 0, any, pdb, intTestFunc, 0, 0))
          475  +  if( SQLITE_OK==rc ){
          476  +    rc = sqlite3_create_function(db, zTest, 2, any, p, testFunc, 0, 0);
          477  +  }
          478  +  if( SQLITE_OK==rc ){
          479  +    rc = sqlite3_create_function(db, zTest, 3, any, p, testFunc, 0, 0);
          480  +  }
          481  +  if( SQLITE_OK==rc ){
          482  +    rc = sqlite3_create_function(db, zTest2, 0, any, pdb, intTestFunc, 0, 0);
          483  +  }
   475    484   #endif
   476         -   );
   477    485   
   478    486   #ifdef SQLITE_TEST
   479    487     sqlite3_free(zTest);
   480    488     sqlite3_free(zTest2);
   481    489   #endif
   482    490   
   483    491     return rc;
   484    492   }
   485    493   
   486    494   #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */

Changes to ext/fts3/fts3_write.c.

   278    278       for(i=0; rc==SQLITE_OK && i<nParam; i++){
   279    279         rc = sqlite3_bind_value(pStmt, i+1, apVal[i]);
   280    280       }
   281    281     }
   282    282     *pp = pStmt;
   283    283     return rc;
   284    284   }
          285  +
          286  +static int fts3SelectDocsize(
          287  +  Fts3Table *pTab,                /* FTS3 table handle */
          288  +  int eStmt,                      /* Either SQL_SELECT_DOCSIZE or DOCTOTAL */
          289  +  sqlite3_int64 iDocid,           /* Docid to bind for SQL_SELECT_DOCSIZE */
          290  +  sqlite3_stmt **ppStmt           /* OUT: Statement handle */
          291  +){
          292  +  sqlite3_stmt *pStmt = 0;        /* Statement requested from fts3SqlStmt() */
          293  +  int rc;                         /* Return code */
          294  +
          295  +  assert( eStmt==SQL_SELECT_DOCSIZE || eStmt==SQL_SELECT_DOCTOTAL );
          296  +
          297  +  rc = fts3SqlStmt(pTab, eStmt, &pStmt, 0);
          298  +  if( rc==SQLITE_OK ){
          299  +    if( eStmt==SQL_SELECT_DOCSIZE ){
          300  +      sqlite3_bind_int64(pStmt, 1, iDocid);
          301  +    }
          302  +    rc = sqlite3_step(pStmt);
          303  +    if( rc!=SQLITE_ROW ){
          304  +      rc = sqlite3_reset(pStmt);
          305  +      if( rc==SQLITE_OK ) rc = SQLITE_CORRUPT;
          306  +      pStmt = 0;
          307  +    }else{
          308  +      rc = SQLITE_OK;
          309  +    }
          310  +  }
          311  +
          312  +  *ppStmt = pStmt;
          313  +  return rc;
          314  +}
          315  +
          316  +int sqlite3Fts3SelectDoctotal(
          317  +  Fts3Table *pTab,                /* Fts3 table handle */
          318  +  sqlite3_stmt **ppStmt           /* OUT: Statement handle */
          319  +){
          320  +  return fts3SelectDocsize(pTab, SQL_SELECT_DOCTOTAL, 0, ppStmt);
          321  +}
          322  +
          323  +int sqlite3Fts3SelectDocsize(
          324  +  Fts3Table *pTab,                /* Fts3 table handle */
          325  +  sqlite3_int64 iDocid,           /* Docid to read size data for */
          326  +  sqlite3_stmt **ppStmt           /* OUT: Statement handle */
          327  +){
          328  +  return fts3SelectDocsize(pTab, SQL_SELECT_DOCSIZE, iDocid, ppStmt);
          329  +}
   285    330   
   286    331   /*
   287    332   ** Similar to fts3SqlStmt(). Except, after binding the parameters in
   288    333   ** array apVal[] to the SQL statement identified by eStmt, the statement
   289    334   ** is executed.
   290    335   **
   291    336   ** Returns SQLITE_OK if the statement is successfully executed, or an
................................................................................
  1067   1112             const char *pEnd = &a[sqlite3_column_bytes(pStmt, 0)];
  1068   1113             a += sqlite3Fts3GetVarint(a, &nDoc);
  1069   1114             while( a<pEnd ){
  1070   1115               a += sqlite3Fts3GetVarint(a, &nByte);
  1071   1116             }
  1072   1117           }
  1073   1118   
  1074         -        pCsr->nRowAvg = (((nByte / nDoc) + pgsz - 1) / pgsz);
         1119  +        pCsr->nRowAvg = (int)(((nByte / nDoc) + pgsz - 1) / pgsz);
  1075   1120         }
  1076   1121         rc = sqlite3_reset(pStmt);
  1077   1122         if( rc!=SQLITE_OK || pCsr->nRowAvg==0 ) return rc;
  1078   1123       }
  1079   1124   
  1080   1125       /* Assume that a blob flows over onto overflow pages if it is larger
  1081   1126       ** than (pgsz-35) bytes in size (the file-format documentation
................................................................................
  1095   1140     return rc;
  1096   1141   }
  1097   1142   
  1098   1143   /*
  1099   1144   ** Free all allocations associated with the iterator passed as the 
  1100   1145   ** second argument.
  1101   1146   */
  1102         -void sqlite3Fts3SegReaderFree(Fts3Table *p, Fts3SegReader *pReader){
         1147  +void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){
  1103   1148     if( pReader && !fts3SegReaderIsPending(pReader) ){
  1104   1149       sqlite3_free(pReader->zTerm);
  1105   1150       if( !fts3SegReaderIsRootOnly(pReader) ){
  1106   1151         sqlite3_free(pReader->aNode);
  1107   1152       }
  1108   1153     }
  1109   1154     sqlite3_free(pReader);
  1110   1155   }
  1111   1156   
  1112   1157   /*
  1113   1158   ** Allocate a new SegReader object.
  1114   1159   */
  1115   1160   int sqlite3Fts3SegReaderNew(
  1116         -  Fts3Table *p,                   /* Virtual table handle */
  1117   1161     int iAge,                       /* Segment "age". */
  1118   1162     sqlite3_int64 iStartLeaf,       /* First leaf to traverse */
  1119   1163     sqlite3_int64 iEndLeaf,         /* Final leaf to traverse */
  1120   1164     sqlite3_int64 iEndBlock,        /* Final block of segment */
  1121   1165     const char *zRoot,              /* Buffer containing root node */
  1122   1166     int nRoot,                      /* Size of buffer containing root node */
  1123   1167     Fts3SegReader **ppReader        /* OUT: Allocated Fts3SegReader */
................................................................................
  1150   1194     }else{
  1151   1195       pReader->iCurrentBlock = iStartLeaf-1;
  1152   1196     }
  1153   1197   
  1154   1198     if( rc==SQLITE_OK ){
  1155   1199       *ppReader = pReader;
  1156   1200     }else{
  1157         -    sqlite3Fts3SegReaderFree(p, pReader);
         1201  +    sqlite3Fts3SegReaderFree(pReader);
  1158   1202     }
  1159   1203     return rc;
  1160   1204   }
  1161   1205   
  1162   1206   /*
  1163   1207   ** This is a comparison function used as a qsort() callback when sorting
  1164   1208   ** an array of pending terms by term. This occurs as part of flushing
................................................................................
  1273   1317   ** current row that pStmt is pointing to. 
  1274   1318   **
  1275   1319   ** If successful, the Fts3SegReader is left pointing to the first term
  1276   1320   ** in the segment and SQLITE_OK is returned. Otherwise, an SQLite error
  1277   1321   ** code is returned.
  1278   1322   */
  1279   1323   static int fts3SegReaderNew(
  1280         -  Fts3Table *p,                   /* Virtual table handle */
  1281   1324     sqlite3_stmt *pStmt,            /* See above */
  1282   1325     int iAge,                       /* Segment "age". */
  1283   1326     Fts3SegReader **ppReader        /* OUT: Allocated Fts3SegReader */
  1284   1327   ){
  1285         -  return sqlite3Fts3SegReaderNew(p, iAge, 
         1328  +  return sqlite3Fts3SegReaderNew(iAge, 
  1286   1329         sqlite3_column_int64(pStmt, 1),
  1287   1330         sqlite3_column_int64(pStmt, 2),
  1288   1331         sqlite3_column_int64(pStmt, 3),
  1289   1332         sqlite3_column_blob(pStmt, 4),
  1290   1333         sqlite3_column_bytes(pStmt, 4),
  1291   1334         ppReader
  1292   1335     );
................................................................................
  2309   2352     ** entries on all leaves of a single segment. 
  2310   2353     */
  2311   2354     assert( SQL_SELECT_LEVEL+1==SQL_SELECT_ALL_LEVEL);
  2312   2355     rc = fts3SqlStmt(p, SQL_SELECT_LEVEL+(iLevel<0), &pStmt, 0);
  2313   2356     if( rc!=SQLITE_OK ) goto finished;
  2314   2357     sqlite3_bind_int(pStmt, 1, iLevel);
  2315   2358     for(i=0; SQLITE_ROW==(sqlite3_step(pStmt)); i++){
  2316         -    rc = fts3SegReaderNew(p, pStmt, i, &apSegment[i]);
         2359  +    rc = fts3SegReaderNew(pStmt, i, &apSegment[i]);
  2317   2360       if( rc!=SQLITE_OK ){
  2318   2361         goto finished;
  2319   2362       }
  2320   2363     }
  2321   2364     rc = sqlite3_reset(pStmt);
  2322   2365     if( pPending ){
  2323   2366       apSegment[i] = pPending;
................................................................................
  2339   2382       rc = fts3SegWriterFlush(p, pWriter, iNewLevel, iIdx);
  2340   2383     }
  2341   2384   
  2342   2385    finished:
  2343   2386     fts3SegWriterFree(pWriter);
  2344   2387     if( apSegment ){
  2345   2388       for(i=0; i<nSegment; i++){
  2346         -      sqlite3Fts3SegReaderFree(p, apSegment[i]);
         2389  +      sqlite3Fts3SegReaderFree(apSegment[i]);
  2347   2390       }
  2348   2391       sqlite3_free(apSegment);
  2349   2392     }
  2350         -  sqlite3Fts3SegReaderFree(p, pPending);
         2393  +  sqlite3Fts3SegReaderFree(pPending);
  2351   2394     sqlite3_reset(pStmt);
  2352   2395     return rc;
  2353   2396   }
  2354   2397   
  2355   2398   
  2356   2399   /* 
  2357   2400   ** Flush the contents of pendingTerms to a level 0 segment.
................................................................................
  2396   2439     ** database. Then delete the SegmentWriter and Fts3SegReader objects
  2397   2440     ** allocated by this function.
  2398   2441     */
  2399   2442     if( rc==SQLITE_OK ){
  2400   2443       rc = fts3SegWriterFlush(p, pWriter, 0, idx);
  2401   2444     }
  2402   2445     fts3SegWriterFree(pWriter);
  2403         -  sqlite3Fts3SegReaderFree(p, pReader);
         2446  +  sqlite3Fts3SegReaderFree(pReader);
  2404   2447   
  2405   2448     if( rc==SQLITE_OK ){
  2406   2449       sqlite3Fts3PendingTermsClear(p);
  2407   2450     }
  2408   2451     return rc;
  2409   2452   }
  2410   2453   
................................................................................
  2439   2482       sqlite3_int64 x;
  2440   2483       j += sqlite3Fts3GetVarint(&zBuf[j], &x);
  2441   2484       assert(j<=nBuf);
  2442   2485       a[i] = (u32)(x & 0xffffffff);
  2443   2486     }
  2444   2487   }
  2445   2488   
  2446         -/*
  2447         -** Fill in the document size auxiliary information for the matchinfo
  2448         -** structure.  The auxiliary information is:
  2449         -**
  2450         -**    N     Total number of documents in the full-text index
  2451         -**    a0    Average length of column 0 over the whole index
  2452         -**    n0    Length of column 0 on the matching row
  2453         -**    ...
  2454         -**    aM    Average length of column M over the whole index
  2455         -**    nM    Length of column M on the matching row
  2456         -**
  2457         -** The fts3MatchinfoDocsizeLocal() routine fills in the nX values.
  2458         -** The fts3MatchinfoDocsizeGlobal() routine fills in N and the aX values.
  2459         -*/
  2460         -int sqlite3Fts3MatchinfoDocsizeLocal(Fts3Cursor *pCur, u32 *a){
  2461         -  const char *pBlob;       /* The BLOB holding %_docsize info */
  2462         -  int nBlob;               /* Size of the BLOB */
  2463         -  sqlite3_stmt *pStmt;     /* Statement for reading and writing */
  2464         -  int i, j;                /* Loop counters */
  2465         -  sqlite3_int64 x;         /* Varint value */
  2466         -  int rc;                  /* Result code from subfunctions */
  2467         -  Fts3Table *p;            /* The FTS table */
  2468         -
  2469         -  p = (Fts3Table*)pCur->base.pVtab;
  2470         -  rc = fts3SqlStmt(p, SQL_SELECT_DOCSIZE, &pStmt, 0);
  2471         -  if( rc ){
  2472         -    return rc;
  2473         -  }
  2474         -  sqlite3_bind_int64(pStmt, 1, pCur->iPrevId);
  2475         -  if( sqlite3_step(pStmt)==SQLITE_ROW ){
  2476         -    nBlob = sqlite3_column_bytes(pStmt, 0);
  2477         -    pBlob = (const char*)sqlite3_column_blob(pStmt, 0);
  2478         -    for(i=j=0; i<p->nColumn && j<nBlob; i++){
  2479         -      j = sqlite3Fts3GetVarint(&pBlob[j], &x);
  2480         -      a[2+i*2] = (u32)(x & 0xffffffff);
  2481         -    }
  2482         -  }
  2483         -  sqlite3_reset(pStmt);
  2484         -  return SQLITE_OK; 
  2485         -}
  2486         -int sqlite3Fts3MatchinfoDocsizeGlobal(Fts3Cursor *pCur, u32 *a){
  2487         -  const char *pBlob;       /* The BLOB holding %_stat info */
  2488         -  int nBlob;               /* Size of the BLOB */
  2489         -  sqlite3_stmt *pStmt;     /* Statement for reading and writing */
  2490         -  int i, j;                /* Loop counters */
  2491         -  sqlite3_int64 x;         /* Varint value */
  2492         -  int nDoc;                /* Number of documents */
  2493         -  int rc;                  /* Result code from subfunctions */
  2494         -  Fts3Table *p;            /* The FTS table */
  2495         -
  2496         -  p = (Fts3Table*)pCur->base.pVtab;
  2497         -  rc = fts3SqlStmt(p, SQL_SELECT_DOCTOTAL, &pStmt, 0);
  2498         -  if( rc ){
  2499         -    return rc;
  2500         -  }
  2501         -  if( sqlite3_step(pStmt)==SQLITE_ROW ){
  2502         -    nBlob = sqlite3_column_bytes(pStmt, 0);
  2503         -    pBlob = (const char*)sqlite3_column_blob(pStmt, 0);
  2504         -    j = sqlite3Fts3GetVarint(pBlob, &x);
  2505         -    a[0] = nDoc = (u32)(x & 0xffffffff);
  2506         -    for(i=0; i<p->nColumn && j<nBlob; i++){
  2507         -      j = sqlite3Fts3GetVarint(&pBlob[j], &x);
  2508         -      a[1+i*2] = ((u32)(x & 0xffffffff) + nDoc/2)/nDoc;
  2509         -    }
  2510         -  }
  2511         -  sqlite3_reset(pStmt);
  2512         -  return SQLITE_OK; 
  2513         -}
  2514         -
  2515   2489   /*
  2516   2490   ** Insert the sizes (in tokens) for each column of the document
  2517   2491   ** with docid equal to p->iPrevDocid.  The sizes are encoded as
  2518   2492   ** a blob of varints.
  2519   2493   */
  2520   2494   static void fts3InsertDocsize(
  2521   2495     int *pRC,         /* Result code */

Changes to ext/rtree/rtree.c.

   109    109   
   110    110   #ifndef SQLITE_AMALGAMATION
   111    111   #include "sqlite3rtree.h"
   112    112   typedef sqlite3_int64 i64;
   113    113   typedef unsigned char u8;
   114    114   typedef unsigned int u32;
   115    115   #endif
          116  +
          117  +/*  The following macro is used to suppress compiler warnings.
          118  +*/
          119  +#ifndef UNUSED_PARAMETER
          120  +# define UNUSED_PARAMETER(x) (void)(x)
          121  +#endif
   116    122   
   117    123   typedef struct Rtree Rtree;
   118    124   typedef struct RtreeCursor RtreeCursor;
   119    125   typedef struct RtreeNode RtreeNode;
   120    126   typedef struct RtreeCell RtreeCell;
   121    127   typedef struct RtreeConstraint RtreeConstraint;
   122    128   typedef struct RtreeMatchArg RtreeMatchArg;
................................................................................
   186    192   ** If an R*-tree "Reinsert" operation is required, the same number of
   187    193   ** cells are removed from the overfull node and reinserted into the tree.
   188    194   */
   189    195   #define RTREE_MINCELLS(p) ((((p)->iNodeSize-4)/(p)->nBytesPerCell)/3)
   190    196   #define RTREE_REINSERT(p) RTREE_MINCELLS(p)
   191    197   #define RTREE_MAXCELLS 51
   192    198   
   193         -/* 
          199  +/*
   194    200   ** The smallest possible node-size is (512-64)==448 bytes. And the largest
   195    201   ** supported cell size is 48 bytes (8 byte rowid + ten 4 byte coordinates).
   196    202   ** Therefore all non-root nodes must contain at least 3 entries. Since 
   197    203   ** 2^40 is greater than 2^64, an r-tree structure always has a depth of
   198    204   ** 40 or less.
   199    205   */
   200    206   #define RTREE_MAX_DEPTH 40
................................................................................
   848    854   ** record (i.e if the scan has finished), or zero otherwise.
   849    855   */
   850    856   static int rtreeEof(sqlite3_vtab_cursor *cur){
   851    857     RtreeCursor *pCsr = (RtreeCursor *)cur;
   852    858     return (pCsr->pNode==0);
   853    859   }
   854    860   
   855         -/* 
          861  +/*
   856    862   ** The r-tree constraint passed as the second argument to this function is
   857    863   ** guaranteed to be a MATCH constraint.
   858    864   */
   859    865   static int testRtreeGeom(
   860    866     Rtree *pRtree,                  /* R-Tree object */
   861    867     RtreeConstraint *pConstraint,   /* MATCH constraint to test */
   862    868     RtreeCell *pCell,               /* Cell to test */
................................................................................
   884    890   ** Return SQLITE_OK if successful or an SQLite error code if an error
   885    891   ** occurs within a geometry callback.
   886    892   */
   887    893   static int testRtreeCell(Rtree *pRtree, RtreeCursor *pCursor, int *pbEof){
   888    894     RtreeCell cell;
   889    895     int ii;
   890    896     int bRes = 0;
          897  +  int rc = SQLITE_OK;
   891    898   
   892    899     nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell);
   893    900     for(ii=0; bRes==0 && ii<pCursor->nConstraint; ii++){
   894    901       RtreeConstraint *p = &pCursor->aConstraint[ii];
   895    902       double cell_min = DCOORD(cell.aCoord[(p->iCoord>>1)*2]);
   896    903       double cell_max = DCOORD(cell.aCoord[(p->iCoord>>1)*2+1]);
   897    904   
................................................................................
   904    911           bRes = p->rValue<cell_min; 
   905    912           break;
   906    913   
   907    914         case RTREE_GE: case RTREE_GT: 
   908    915           bRes = p->rValue>cell_max; 
   909    916           break;
   910    917   
   911         -      case RTREE_EQ: 
          918  +      case RTREE_EQ:
   912    919           bRes = (p->rValue>cell_max || p->rValue<cell_min);
   913    920           break;
   914    921   
   915    922         default: {
   916         -        int rc;
   917    923           assert( p->op==RTREE_MATCH );
   918    924           rc = testRtreeGeom(pRtree, p, &cell, &bRes);
   919         -        if( rc!=SQLITE_OK ){
   920         -          return rc;
   921         -        }
   922    925           bRes = !bRes;
   923    926           break;
   924    927         }
   925    928       }
   926    929     }
   927    930   
   928    931     *pbEof = bRes;
   929         -  return SQLITE_OK;
          932  +  return rc;
   930    933   }
   931    934   
   932    935   /* 
   933    936   ** Test if the cell that cursor pCursor currently points to
   934    937   ** would be filtered (excluded) by the constraints in the 
   935    938   ** pCursor->aConstraint[] array. If so, set *pbEof to true before
   936    939   ** returning. If the cell is not filtered (excluded) by the constraints,
................................................................................
  1005   1008   
  1006   1009     if( iHeight==0 ){
  1007   1010       rc = testRtreeEntry(pRtree, pCursor, &isEof);
  1008   1011     }else{
  1009   1012       rc = testRtreeCell(pRtree, pCursor, &isEof);
  1010   1013     }
  1011   1014     if( rc!=SQLITE_OK || isEof || iHeight==0 ){
  1012         -    *pEof = isEof;
  1013         -    return rc;
         1015  +    goto descend_to_cell_out;
  1014   1016     }
  1015   1017   
  1016   1018     iRowid = nodeGetRowid(pRtree, pCursor->pNode, pCursor->iCell);
  1017   1019     rc = nodeAcquire(pRtree, iRowid, pCursor->pNode, &pChild);
  1018   1020     if( rc!=SQLITE_OK ){
  1019         -    return rc;
         1021  +    goto descend_to_cell_out;
  1020   1022     }
  1021   1023   
  1022   1024     nodeRelease(pRtree, pCursor->pNode);
  1023   1025     pCursor->pNode = pChild;
  1024   1026     isEof = 1;
  1025   1027     for(ii=0; isEof && ii<NCELL(pChild); ii++){
  1026   1028       pCursor->iCell = ii;
  1027   1029       rc = descendToCell(pRtree, pCursor, iHeight-1, &isEof);
  1028   1030       if( rc!=SQLITE_OK ){
  1029         -      return rc;
         1031  +      goto descend_to_cell_out;
  1030   1032       }
  1031   1033     }
  1032   1034   
  1033   1035     if( isEof ){
  1034   1036       assert( pCursor->pNode==pChild );
  1035   1037       nodeReference(pSavedNode);
  1036   1038       nodeRelease(pRtree, pChild);
  1037   1039       pCursor->pNode = pSavedNode;
  1038   1040       pCursor->iCell = iSavedCell;
  1039   1041     }
  1040   1042   
         1043  +descend_to_cell_out:
  1041   1044     *pEof = isEof;
  1042         -  return SQLITE_OK;
         1045  +  return rc;
  1043   1046   }
  1044   1047   
  1045   1048   /*
  1046   1049   ** One of the cells in node pNode is guaranteed to have a 64-bit 
  1047   1050   ** integer value equal to iRowid. Return the index of this cell.
  1048   1051   */
  1049   1052   static int nodeRowidIndex(
................................................................................
  1191   1194     int nBlob;
  1192   1195   
  1193   1196     /* Check that value is actually a blob. */
  1194   1197     if( !sqlite3_value_type(pValue)==SQLITE_BLOB ) return SQLITE_ERROR;
  1195   1198   
  1196   1199     /* Check that the blob is roughly the right size. */
  1197   1200     nBlob = sqlite3_value_bytes(pValue);
  1198         -  if( nBlob<sizeof(RtreeMatchArg) 
         1201  +  if( nBlob<(int)sizeof(RtreeMatchArg) 
  1199   1202      || ((nBlob-sizeof(RtreeMatchArg))%sizeof(double))!=0
  1200   1203     ){
  1201   1204       return SQLITE_ERROR;
  1202   1205     }
  1203   1206   
  1204   1207     pGeom = (sqlite3_rtree_geometry *)sqlite3_malloc(
  1205   1208         sizeof(sqlite3_rtree_geometry) + nBlob
................................................................................
  1206   1209     );
  1207   1210     if( !pGeom ) return SQLITE_NOMEM;
  1208   1211     memset(pGeom, 0, sizeof(sqlite3_rtree_geometry));
  1209   1212     p = (RtreeMatchArg *)&pGeom[1];
  1210   1213   
  1211   1214     memcpy(p, sqlite3_value_blob(pValue), nBlob);
  1212   1215     if( p->magic!=RTREE_GEOMETRY_MAGIC 
  1213         -   || nBlob!=(sizeof(RtreeMatchArg) + (p->nParam-1)*sizeof(double))
         1216  +   || nBlob!=(int)(sizeof(RtreeMatchArg) + (p->nParam-1)*sizeof(double))
  1214   1217     ){
  1215   1218       sqlite3_free(pGeom);
  1216   1219       return SQLITE_ERROR;
  1217   1220     }
  1218   1221   
  1219   1222     pGeom->pContext = p->pContext;
  1220   1223     pGeom->nParam = p->nParam;
................................................................................
  1352   1355   static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
  1353   1356     int rc = SQLITE_OK;
  1354   1357     int ii, cCol;
  1355   1358   
  1356   1359     int iIdx = 0;
  1357   1360     char zIdxStr[RTREE_MAX_DIMENSIONS*8+1];
  1358   1361     memset(zIdxStr, 0, sizeof(zIdxStr));
         1362  +  UNUSED_PARAMETER(tab);
  1359   1363   
  1360   1364     assert( pIdxInfo->idxStr==0 );
  1361   1365     for(ii=0; ii<pIdxInfo->nConstraint; ii++){
  1362   1366       struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];
  1363   1367   
  1364   1368       if( p->usable && p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
  1365   1369         /* We have an equality constraint on the rowid. Use strategy 1. */
................................................................................
  1525   1529     int ii;
  1526   1530     float overlap = 0.0;
  1527   1531     for(ii=0; ii<nCell; ii++){
  1528   1532   #if VARIANT_RSTARTREE_CHOOSESUBTREE
  1529   1533       if( ii!=iExclude )
  1530   1534   #else
  1531   1535       assert( iExclude==-1 );
         1536  +    UNUSED_PARAMETER(iExclude);
  1532   1537   #endif
  1533   1538       {
  1534   1539         int jj;
  1535   1540         float o = 1.0;
  1536   1541         for(jj=0; jj<(pRtree->nDim*2); jj+=2){
  1537   1542           double x1;
  1538   1543           double x2;
................................................................................
  3111   3116   */
  3112   3117   static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
  3113   3118     char *zText = 0;
  3114   3119     RtreeNode node;
  3115   3120     Rtree tree;
  3116   3121     int ii;
  3117   3122   
         3123  +  UNUSED_PARAMETER(nArg);
  3118   3124     memset(&node, 0, sizeof(RtreeNode));
  3119   3125     memset(&tree, 0, sizeof(Rtree));
  3120   3126     tree.nDim = sqlite3_value_int(apArg[0]);
  3121   3127     tree.nBytesPerCell = 8 + 8 * tree.nDim;
  3122   3128     node.zData = (u8 *)sqlite3_value_blob(apArg[1]);
  3123   3129   
  3124   3130     for(ii=0; ii<NCELL(&node); ii++){
................................................................................
  3144   3150       }
  3145   3151     }
  3146   3152     
  3147   3153     sqlite3_result_text(ctx, zText, -1, sqlite3_free);
  3148   3154   }
  3149   3155   
  3150   3156   static void rtreedepth(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
         3157  +  UNUSED_PARAMETER(nArg);
  3151   3158     if( sqlite3_value_type(apArg[0])!=SQLITE_BLOB 
  3152   3159      || sqlite3_value_bytes(apArg[0])<2
  3153   3160     ){
  3154   3161       sqlite3_result_error(ctx, "Invalid argument to rtreedepth()", -1); 
  3155   3162     }else{
  3156   3163       u8 *zBlob = (u8 *)sqlite3_value_blob(apArg[0]);
  3157   3164       sqlite3_result_int(ctx, readInt16(zBlob));
................................................................................
  3165   3172   */
  3166   3173   int sqlite3RtreeInit(sqlite3 *db){
  3167   3174     const int utf8 = SQLITE_UTF8;
  3168   3175     int rc;
  3169   3176   
  3170   3177     rc = sqlite3_create_function(db, "rtreenode", 2, utf8, 0, rtreenode, 0, 0);
  3171   3178     if( rc==SQLITE_OK ){
  3172         -    int utf8 = SQLITE_UTF8;
  3173   3179       rc = sqlite3_create_function(db, "rtreedepth", 1, utf8, 0,rtreedepth, 0, 0);
  3174   3180     }
  3175   3181     if( rc==SQLITE_OK ){
  3176   3182       void *c = (void *)RTREE_COORD_REAL32;
  3177   3183       rc = sqlite3_create_module_v2(db, "rtree", &rtreeModule, c, 0);
  3178   3184     }
  3179   3185     if( rc==SQLITE_OK ){

Changes to src/btree.c.

  1707   1707     u8 nReserve;                   /* Byte of unused space on each page */
  1708   1708     unsigned char zDbHeader[100];  /* Database header content */
  1709   1709   
  1710   1710     /* True if opening an ephemeral, temporary database */
  1711   1711     const int isTempDb = zFilename==0 || zFilename[0]==0;
  1712   1712   
  1713   1713     /* Set the variable isMemdb to true for an in-memory database, or 
  1714         -  ** false for a file-based database. This symbol is only required if
  1715         -  ** either of the shared-data or autovacuum features are compiled 
  1716         -  ** into the library.
         1714  +  ** false for a file-based database.
  1717   1715     */
  1718         -#if !defined(SQLITE_OMIT_SHARED_CACHE) || !defined(SQLITE_OMIT_AUTOVACUUM)
  1719         -  #ifdef SQLITE_OMIT_MEMORYDB
  1720         -    const int isMemdb = 0;
  1721         -  #else
  1722         -    const int isMemdb = (zFilename && strcmp(zFilename, ":memory:")==0)
  1723         -                         || (isTempDb && sqlite3TempInMemory(db));
  1724         -  #endif
         1716  +#ifdef SQLITE_OMIT_MEMORYDB
         1717  +  const int isMemdb = 0;
         1718  +#else
         1719  +  const int isMemdb = (zFilename && strcmp(zFilename, ":memory:")==0)
         1720  +                       || (isTempDb && sqlite3TempInMemory(db));
  1725   1721   #endif
  1726   1722   
  1727   1723     assert( db!=0 );
  1728   1724     assert( sqlite3_mutex_held(db->mutex) );
  1729   1725     assert( (flags&0xff)==flags );   /* flags fit in 8 bits */
  1730   1726   
  1731   1727     /* Only a BTREE_SINGLE database can be BTREE_UNORDERED */

Changes to src/expr.c.

  1651   1651           SelectDest dest;
  1652   1652           ExprList *pEList;
  1653   1653   
  1654   1654           assert( !isRowid );
  1655   1655           sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
  1656   1656           dest.affinity = (u8)affinity;
  1657   1657           assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
         1658  +        pExpr->x.pSelect->iLimit = 0;
  1658   1659           if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){
  1659   1660             return 0;
  1660   1661           }
  1661   1662           pEList = pExpr->x.pSelect->pEList;
  1662   1663           if( ALWAYS(pEList!=0 && pEList->nExpr>0) ){ 
  1663   1664             keyInfo.aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
  1664   1665                 pEList->a[0].pExpr);
................................................................................
  1751   1752           dest.eDest = SRT_Exists;
  1752   1753           sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iParm);
  1753   1754           VdbeComment((v, "Init EXISTS result"));
  1754   1755         }
  1755   1756         sqlite3ExprDelete(pParse->db, pSel->pLimit);
  1756   1757         pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0,
  1757   1758                                     &sqlite3IntTokens[1]);
         1759  +      pSel->iLimit = 0;
  1758   1760         if( sqlite3Select(pParse, pSel, &dest) ){
  1759   1761           return 0;
  1760   1762         }
  1761   1763         rReg = dest.iParm;
  1762   1764         ExprSetIrreducible(pExpr);
  1763   1765         break;
  1764   1766       }
................................................................................
  3034   3036     return WRC_Continue;
  3035   3037   }
  3036   3038   
  3037   3039   /*
  3038   3040   ** Preevaluate constant subexpressions within pExpr and store the
  3039   3041   ** results in registers.  Modify pExpr so that the constant subexpresions
  3040   3042   ** are TK_REGISTER opcodes that refer to the precomputed values.
         3043  +**
         3044  +** This routine is a no-op if the jump to the cookie-check code has
         3045  +** already occur.  Since the cookie-check jump is generated prior to
         3046  +** any other serious processing, this check ensures that there is no
         3047  +** way to accidently bypass the constant initializations.
         3048  +**
         3049  +** This routine is also a no-op if the SQLITE_FactorOutConst optimization
         3050  +** is disabled via the sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS)
         3051  +** interface.  This allows test logic to verify that the same answer is
         3052  +** obtained for queries regardless of whether or not constants are
         3053  +** precomputed into registers or if they are inserted in-line.
  3041   3054   */
  3042   3055   void sqlite3ExprCodeConstants(Parse *pParse, Expr *pExpr){
  3043   3056     Walker w;
         3057  +  if( pParse->cookieGoto ) return;
         3058  +  if( (pParse->db->flags & SQLITE_FactorOutConst)!=0 ) return;
  3044   3059     w.xExprCallback = evalConstExpr;
  3045   3060     w.xSelectCallback = 0;
  3046   3061     w.pParse = pParse;
  3047   3062     sqlite3WalkExpr(&w, pExpr);
  3048   3063   }
  3049   3064   
  3050   3065   

Changes to src/os_unix.c.

  5102   5102   ** SQLite calls this function immediately after a call to unixDlSym() or
  5103   5103   ** unixDlOpen() fails (returns a null pointer). If a more detailed error
  5104   5104   ** message is available, it is written to zBufOut. If no error message
  5105   5105   ** is available, zBufOut is left unmodified and SQLite uses a default
  5106   5106   ** error message.
  5107   5107   */
  5108   5108   static void unixDlError(sqlite3_vfs *NotUsed, int nBuf, char *zBufOut){
  5109         -  char *zErr;
         5109  +  const char *zErr;
  5110   5110     UNUSED_PARAMETER(NotUsed);
  5111   5111     unixEnterMutex();
  5112   5112     zErr = dlerror();
  5113   5113     if( zErr ){
  5114   5114       sqlite3_snprintf(nBuf, zBufOut, "%s", zErr);
  5115   5115     }
  5116   5116     unixLeaveMutex();
................................................................................
  5239   5239   ** On success, return 0.  Return 1 if the time and date cannot be found.
  5240   5240   */
  5241   5241   static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
  5242   5242     static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
  5243   5243   #if defined(NO_GETTOD)
  5244   5244     time_t t;
  5245   5245     time(&t);
  5246         -  *piNow = ((sqlite3_int64)i)*1000 + unixEpoch;
         5246  +  *piNow = ((sqlite3_int64)t)*1000 + unixEpoch;
  5247   5247   #elif OS_VXWORKS
  5248   5248     struct timespec sNow;
  5249   5249     clock_gettime(CLOCK_REALTIME, &sNow);
  5250   5250     *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_nsec/1000000;
  5251   5251   #else
  5252   5252     struct timeval sNow;
  5253   5253     gettimeofday(&sNow, 0);
................................................................................
  5719   5719     int rc = -1;
  5720   5720     UNUSED_PARAMETER(myHostID);
  5721   5721   
  5722   5722     /* create a new path by replace the trailing '-conch' with '-break' */
  5723   5723     pathLen = strlcpy(tPath, cPath, MAXPATHLEN);
  5724   5724     if( pathLen>MAXPATHLEN || pathLen<6 || 
  5725   5725        (strlcpy(&tPath[pathLen-5], "break", 6) != 5) ){
  5726         -    sprintf(errmsg, "path error (len %d)", (int)pathLen);
         5726  +    sqlite3_snprintf(sizeof(errmsg),errmsg,"path error (len %d)",(int)pathLen);
  5727   5727       goto end_breaklock;
  5728   5728     }
  5729   5729     /* read the conch content */
  5730   5730     readLen = pread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0);
  5731   5731     if( readLen<PROXY_PATHINDEX ){
  5732         -    sprintf(errmsg, "read error (len %d)", (int)readLen);
         5732  +    sqlite3_snprintf(sizeof(errmsg),errmsg,"read error (len %d)",(int)readLen);
  5733   5733       goto end_breaklock;
  5734   5734     }
  5735   5735     /* write it out to the temporary break file */
  5736   5736     fd = open(tPath, (O_RDWR|O_CREAT|O_EXCL), SQLITE_DEFAULT_FILE_PERMISSIONS);
  5737   5737     if( fd<0 ){
  5738         -    sprintf(errmsg, "create failed (%d)", errno);
         5738  +    sqlite3_snprintf(sizeof(errmsg), errmsg, "create failed (%d)", errno);
  5739   5739       goto end_breaklock;
  5740   5740     }
  5741   5741     if( pwrite(fd, buf, readLen, 0) != (ssize_t)readLen ){
  5742         -    sprintf(errmsg, "write failed (%d)", errno);
         5742  +    sqlite3_snprintf(sizeof(errmsg), errmsg, "write failed (%d)", errno);
  5743   5743       goto end_breaklock;
  5744   5744     }
  5745   5745     if( rename(tPath, cPath) ){
  5746         -    sprintf(errmsg, "rename failed (%d)", errno);
         5746  +    sqlite3_snprintf(sizeof(errmsg), errmsg, "rename failed (%d)", errno);
  5747   5747       goto end_breaklock;
  5748   5748     }
  5749   5749     rc = 0;
  5750   5750     fprintf(stderr, "broke stale lock on %s\n", cPath);
  5751   5751     close(conchFile->h);
  5752   5752     conchFile->h = fd;
  5753   5753     conchFile->openFlags = O_RDWR | O_CREAT;

Changes to src/pager.c.

  3479   3479   **
  3480   3480   ** Regardless of mxPage, return the current maximum page count.
  3481   3481   */
  3482   3482   int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){
  3483   3483     if( mxPage>0 ){
  3484   3484       pPager->mxPgno = mxPage;
  3485   3485     }
  3486         -  if( pPager->eState!=PAGER_OPEN && pPager->mxPgno<pPager->dbSize ){
  3487         -    pPager->mxPgno = pPager->dbSize;
  3488         -  }
         3486  +  assert( pPager->eState!=PAGER_OPEN );      /* Called only by OP_MaxPgcnt */
         3487  +  assert( pPager->mxPgno>=pPager->dbSize );  /* OP_MaxPgcnt enforces this */
  3489   3488     return pPager->mxPgno;
  3490   3489   }
  3491   3490   
  3492   3491   /*
  3493   3492   ** The following set of routines are used to disable the simulated
  3494   3493   ** I/O error mechanism.  These routines are used to avoid simulated
  3495   3494   ** errors in places where we do not care about errors.

Changes to src/pragma.c.

    31     31                                /* 123456789 123456789 */
    32     32     static const char zText[] = "onoffalseyestruefull";
    33     33     static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 16};
    34     34     static const u8 iLength[] = {2, 2, 3, 5, 3, 4, 4};
    35     35     static const u8 iValue[] =  {1, 0, 0, 0, 1, 1, 2};
    36     36     int i, n;
    37     37     if( sqlite3Isdigit(*z) ){
    38         -    return (u8)atoi(z);
           38  +    return (u8)sqlite3Atoi(z);
    39     39     }
    40     40     n = sqlite3Strlen30(z);
    41     41     for(i=0; i<ArraySize(iLength); i++){
    42     42       if( iLength[i]==n && sqlite3StrNICmp(&zText[iOffset[i]],z,n)==0 ){
    43     43         return iValue[i];
    44     44       }
    45     45     }
................................................................................
    72     72   ** acceptable, as are their numeric equivalents: 0, 1 and 2 respectively.
    73     73   */
    74     74   static int getAutoVacuum(const char *z){
    75     75     int i;
    76     76     if( 0==sqlite3StrICmp(z, "none") ) return BTREE_AUTOVACUUM_NONE;
    77     77     if( 0==sqlite3StrICmp(z, "full") ) return BTREE_AUTOVACUUM_FULL;
    78     78     if( 0==sqlite3StrICmp(z, "incremental") ) return BTREE_AUTOVACUUM_INCR;
    79         -  i = atoi(z);
           79  +  i = sqlite3Atoi(z);
    80     80     return (u8)((i>=0&&i<=2)?i:0);
    81     81   }
    82     82   #endif /* ifndef SQLITE_OMIT_AUTOVACUUM */
    83     83   
    84     84   #ifndef SQLITE_OMIT_PAGER_PRAGMAS
    85     85   /*
    86     86   ** Interpret the given string as a temp db location. Return 1 for file
................................................................................
   381    381         sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", SQLITE_STATIC);
   382    382         pParse->nMem += 2;
   383    383         addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
   384    384         sqlite3VdbeChangeP1(v, addr, iDb);
   385    385         sqlite3VdbeChangeP1(v, addr+1, iDb);
   386    386         sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE);
   387    387       }else{
   388         -      int size = atoi(zRight);
          388  +      int size = sqlite3Atoi(zRight);
   389    389         if( size<0 ) size = -size;
   390    390         sqlite3BeginWriteOperation(pParse, 0, iDb);
   391    391         sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
   392    392         sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1);
   393    393         pDb->pSchema->cache_size = size;
   394    394         sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
   395    395       }
................................................................................
   410    410       if( !zRight ){
   411    411         i64 size = ALWAYS(pBt) ? sqlite3BtreeGetPageSize(pBt) : 0;
   412    412         returnSingleInt(pParse, "page_size", &size);
   413    413       }else{
   414    414         /* Malloc may fail when setting the page-size, as there is an internal
   415    415         ** buffer that the pager module resizes using sqlite3_realloc().
   416    416         */
   417         -      db->nextPagesize = atoi(zRight);
          417  +      db->nextPagesize = sqlite3Atoi(zRight);
   418    418         if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
   419    419           db->mallocFailed = 1;
   420    420         }
   421    421       }
   422    422     }else
   423    423   
   424         -  /*
   425         -  **  PRAGMA [database.]max_page_count
   426         -  **  PRAGMA [database.]max_page_count=N
   427         -  **
   428         -  ** The first form reports the current setting for the
   429         -  ** maximum number of pages in the database file.  The 
   430         -  ** second form attempts to change this setting.  Both
   431         -  ** forms return the current setting.
   432         -  */
   433         -  if( sqlite3StrICmp(zLeft,"max_page_count")==0 ){
   434         -    Btree *pBt = pDb->pBt;
   435         -    i64 newMax = 0;
   436         -    assert( pBt!=0 );
   437         -    if( zRight ){
   438         -      newMax = atoi(zRight);
   439         -    }
   440         -    if( ALWAYS(pBt) ){
   441         -      newMax = sqlite3BtreeMaxPageCount(pBt, (int)newMax);
   442         -    }
   443         -    returnSingleInt(pParse, "max_page_count", &newMax);
   444         -  }else
   445         -
   446    424     /*
   447    425     **  PRAGMA [database.]secure_delete
   448    426     **  PRAGMA [database.]secure_delete=ON/OFF
   449    427     **
   450    428     ** The first form reports the current setting for the
   451    429     ** secure_delete flag.  The second form changes the secure_delete
   452    430     ** flag setting and reports thenew value.
................................................................................
   465    443         }
   466    444       }
   467    445       b = sqlite3BtreeSecureDelete(pBt, b);
   468    446       returnSingleInt(pParse, "secure_delete", &b);
   469    447     }else
   470    448   
   471    449     /*
          450  +  **  PRAGMA [database.]max_page_count
          451  +  **  PRAGMA [database.]max_page_count=N
          452  +  **
          453  +  ** The first form reports the current setting for the
          454  +  ** maximum number of pages in the database file.  The 
          455  +  ** second form attempts to change this setting.  Both
          456  +  ** forms return the current setting.
          457  +  **
   472    458     **  PRAGMA [database.]page_count
   473    459     **
   474    460     ** Return the number of pages in the specified database.
   475    461     */
   476         -  if( sqlite3StrICmp(zLeft,"page_count")==0 ){
          462  +  if( sqlite3StrICmp(zLeft,"page_count")==0
          463  +   || sqlite3StrICmp(zLeft,"max_page_count")==0
          464  +  ){
   477    465       int iReg;
   478    466       if( sqlite3ReadSchema(pParse) ) goto pragma_out;
   479    467       sqlite3CodeVerifySchema(pParse, iDb);
   480    468       iReg = ++pParse->nMem;
   481         -    sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg);
          469  +    if( zLeft[0]=='p' ){
          470  +      sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg);
          471  +    }else{
          472  +      sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg, sqlite3Atoi(zRight));
          473  +    }
   482    474       sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1);
   483    475       sqlite3VdbeSetNumCols(v, 1);
   484         -    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "page_count", SQLITE_STATIC);
          476  +    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT);
   485    477     }else
   486    478   
   487    479     /*
   488    480     **  PRAGMA [database.]locking_mode
   489    481     **  PRAGMA [database.]locking_mode = (normal|exclusive)
   490    482     */
   491    483     if( sqlite3StrICmp(zLeft,"locking_mode")==0 ){
................................................................................
   700    692     */
   701    693     if( sqlite3StrICmp(zLeft,"cache_size")==0 ){
   702    694       if( sqlite3ReadSchema(pParse) ) goto pragma_out;
   703    695       if( !zRight ){
   704    696         i64 cacheSize = pDb->pSchema->cache_size;
   705    697         returnSingleInt(pParse, "cache_size", &cacheSize);
   706    698       }else{
   707         -      int size = atoi(zRight);
          699  +      int size = sqlite3Atoi(zRight);
   708    700         if( size<0 ) size = -size;
   709    701         pDb->pSchema->cache_size = size;
   710    702         sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
   711    703       }
   712    704     }else
   713    705   
   714    706     /*
................................................................................
  1095   1087       pParse->nMem = 6;
  1096   1088       sqlite3VdbeSetNumCols(v, 1);
  1097   1089       sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", SQLITE_STATIC);
  1098   1090   
  1099   1091       /* Set the maximum error count */
  1100   1092       mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
  1101   1093       if( zRight ){
  1102         -      mxErr = atoi(zRight);
         1094  +      sqlite3GetInt32(zRight, &mxErr);
  1103   1095         if( mxErr<=0 ){
  1104   1096           mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
  1105   1097         }
  1106   1098       }
  1107   1099       sqlite3VdbeAddOp2(v, OP_Integer, mxErr, 1);  /* reg[1] holds errors left */
  1108   1100   
  1109   1101       /* Do an integrity check on each database file */
................................................................................
  1352   1344         static const VdbeOpList setCookie[] = {
  1353   1345           { OP_Transaction,    0,  1,  0},    /* 0 */
  1354   1346           { OP_Integer,        0,  1,  0},    /* 1 */
  1355   1347           { OP_SetCookie,      0,  0,  1},    /* 2 */
  1356   1348         };
  1357   1349         int addr = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie);
  1358   1350         sqlite3VdbeChangeP1(v, addr, iDb);
  1359         -      sqlite3VdbeChangeP1(v, addr+1, atoi(zRight));
         1351  +      sqlite3VdbeChangeP1(v, addr+1, sqlite3Atoi(zRight));
  1360   1352         sqlite3VdbeChangeP1(v, addr+2, iDb);
  1361   1353         sqlite3VdbeChangeP2(v, addr+2, iCookie);
  1362   1354       }else{
  1363   1355         /* Read the specified cookie value */
  1364   1356         static const VdbeOpList readCookie[] = {
  1365   1357           { OP_Transaction,     0,  0,  0},    /* 0 */
  1366   1358           { OP_ReadCookie,      0,  1,  0},    /* 1 */
................................................................................
  1414   1406     ** Configure a database connection to automatically checkpoint a database
  1415   1407     ** after accumulating N frames in the log. Or query for the current value
  1416   1408     ** of N.
  1417   1409     */
  1418   1410     if( sqlite3StrICmp(zLeft, "wal_autocheckpoint")==0 ){
  1419   1411       i64 walArg = 0;
  1420   1412       if( zRight ){
  1421         -      int nAuto = atoi(zRight);
  1422         -      sqlite3_wal_autocheckpoint(db, nAuto);
         1413  +      sqlite3_wal_autocheckpoint(db, sqlite3Atoi(zRight));
  1423   1414       }
  1424   1415       if( db->xWalCallback==sqlite3WalDefaultHook ){
  1425   1416         walArg = SQLITE_PTR_TO_INT(db->pWalArg);
  1426   1417       }
  1427   1418       returnSingleInt(pParse, "wal_autocheckpoint", &walArg);
  1428   1419     }else
  1429   1420   #endif

Changes to src/prepare.c.

    78     78       */
    79     79       int rc;
    80     80       sqlite3_stmt *pStmt;
    81     81       TESTONLY(int rcp);            /* Return code from sqlite3_prepare() */
    82     82   
    83     83       assert( db->init.busy );
    84     84       db->init.iDb = iDb;
    85         -    db->init.newTnum = atoi(argv[1]);
           85  +    db->init.newTnum = sqlite3Atoi(argv[1]);
    86     86       db->init.orphanTrigger = 0;
    87     87       TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0);
    88     88       rc = db->errCode;
    89     89       assert( (rc&0xFF)==(rcp&0xFF) );
    90     90       db->init.iDb = 0;
    91     91       if( SQLITE_OK!=rc ){
    92     92         if( db->init.orphanTrigger ){

Changes to src/select.c.

  3761   3761           isAgg = 1;
  3762   3762           p->selFlags |= SF_Aggregate;
  3763   3763         }
  3764   3764         i = -1;
  3765   3765       }else{
  3766   3766         sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
  3767   3767         assert( pItem->isPopulated==0 );
  3768         -      explainSetInteger(pItem->iSelectId, pParse->iNextSelectId);
         3768  +      explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
  3769   3769         sqlite3Select(pParse, pSub, &dest);
  3770   3770         pItem->isPopulated = 1;
  3771   3771         pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
  3772   3772       }
  3773   3773       if( /*pParse->nErr ||*/ db->mallocFailed ){
  3774   3774         goto select_end;
  3775   3775       }

Changes to src/sqlite.h.in.

  4831   4831   ** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] -
  4832   4832   ** it must exist and there must be either a blob or text value stored in
  4833   4833   ** the nominated column.)^ ^If the new row is not present in the table, or if
  4834   4834   ** it does not contain a blob or text value, or if another error occurs, an
  4835   4835   ** SQLite error code is returned and the blob handle is considered aborted.
  4836   4836   ** ^All subsequent calls to [sqlite3_blob_read()], [sqlite3_blob_write()] or
  4837   4837   ** [sqlite3_blob_reopen()] on an aborted blob handle immediately return
  4838         -** SQLITE_ABORT.
         4838  +** SQLITE_ABORT. ^Calling [sqlite3_blob_bytes()] on an aborted blob handle
         4839  +** always returns zero.
  4839   4840   **
  4840   4841   ** ^This function sets the database handle error code and message.
  4841   4842   */
  4842   4843   SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
  4843   4844   
  4844   4845   /*
  4845   4846   ** CAPI3REF: Close A BLOB Handle

Changes to src/sqliteInt.h.

   930    930   */
   931    931   #define SQLITE_QueryFlattener 0x01        /* Disable query flattening */
   932    932   #define SQLITE_ColumnCache    0x02        /* Disable the column cache */
   933    933   #define SQLITE_IndexSort      0x04        /* Disable indexes for sorting */
   934    934   #define SQLITE_IndexSearch    0x08        /* Disable indexes for searching */
   935    935   #define SQLITE_IndexCover     0x10        /* Disable index covering table */
   936    936   #define SQLITE_GroupByOrder   0x20        /* Disable GROUPBY cover of ORDERBY */
          937  +#define SQLITE_FactorOutConst 0x40        /* Disable factoring out constants */
   937    938   #define SQLITE_OptMask        0xff        /* Mask of all disablable opts */
   938    939   
   939    940   /*
   940    941   ** Possible values for the sqlite.magic field.
   941    942   ** The numbers are obtained at random and have no special meaning, other
   942    943   ** than being distinct from one another.
   943    944   */
................................................................................
  1818   1819       char *zName;      /* Name of the table */
  1819   1820       char *zAlias;     /* The "B" part of a "A AS B" phrase.  zName is the "A" */
  1820   1821       Table *pTab;      /* An SQL table corresponding to zName */
  1821   1822       Select *pSelect;  /* A SELECT statement used in place of a table name */
  1822   1823       u8 isPopulated;   /* Temporary table associated with SELECT is populated */
  1823   1824       u8 jointype;      /* Type of join between this able and the previous */
  1824   1825       u8 notIndexed;    /* True if there is a NOT INDEXED clause */
         1826  +#ifndef SQLITE_OMIT_EXPLAIN
         1827  +    u8 iSelectId;     /* If pSelect!=0, the id of the sub-select in EQP */
         1828  +#endif
  1825   1829       int iCursor;      /* The VDBE cursor number used to access this table */
  1826   1830       Expr *pOn;        /* The ON clause of a join */
  1827   1831       IdList *pUsing;   /* The USING clause of a join */
  1828   1832       Bitmask colUsed;  /* Bit N (1<<N) set if column N of pTab is used */
  1829   1833       char *zIndex;     /* Identifier from "INDEXED BY <zIndex>" clause */
  1830   1834       Index *pIndex;    /* Index structure corresponding to zIndex, if any */
  1831         -#ifndef SQLITE_OMIT_EXPLAIN
  1832         -    int iSelectId;    /* If pSelect!=0, the id of the sub-select in EQP */
  1833         -#endif
  1834   1835     } a[1];             /* One entry for each identifier on the list */
  1835   1836   };
  1836   1837   
  1837   1838   /*
  1838   1839   ** Permitted values of the SrcList.a.jointype field
  1839   1840   */
  1840   1841   #define JT_INNER     0x0001    /* Any kind of inner or cross join */
................................................................................
  2836   2837   int sqlite3FixSrcList(DbFixer*, SrcList*);
  2837   2838   int sqlite3FixSelect(DbFixer*, Select*);
  2838   2839   int sqlite3FixExpr(DbFixer*, Expr*);
  2839   2840   int sqlite3FixExprList(DbFixer*, ExprList*);
  2840   2841   int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
  2841   2842   int sqlite3AtoF(const char *z, double*, int, u8);
  2842   2843   int sqlite3GetInt32(const char *, int*);
         2844  +int sqlite3Atoi(const char*);
  2843   2845   int sqlite3Utf16ByteLen(const void *pData, int nChar);
  2844   2846   int sqlite3Utf8CharLen(const char *pData, int nByte);
  2845   2847   int sqlite3Utf8Read(const u8*, const u8**);
  2846   2848   
  2847   2849   /*
  2848   2850   ** Routines to read and write variable-length integers.  These used to
  2849   2851   ** be defined locally, but now we use the varint routines in the util.c

Changes to src/test1.c.

  5421   5421     }
  5422   5422     if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
  5423   5423     rc = printExplainQueryPlan(pStmt);
  5424   5424     Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
  5425   5425     return TCL_OK;
  5426   5426   }
  5427   5427   #endif /* SQLITE_OMIT_EXPLAIN */
         5428  +
         5429  +/*
         5430  +**      optimization_control DB OPT BOOLEAN
         5431  +**
         5432  +** Enable or disable query optimizations using the sqlite3_test_control()
         5433  +** interface.  Disable if BOOLEAN is false and enable if BOOLEAN is true.
         5434  +** OPT is the name of the optimization to be disabled.
         5435  +*/
         5436  +static int optimization_control(
         5437  +  void * clientData,
         5438  +  Tcl_Interp *interp,
         5439  +  int objc,
         5440  +  Tcl_Obj *CONST objv[]
         5441  +){
         5442  +  int i;
         5443  +  sqlite3 *db;
         5444  +  const char *zOpt;
         5445  +  int onoff;
         5446  +  int mask;
         5447  +  static const struct {
         5448  +    const char *zOptName;
         5449  +    int mask;
         5450  +  } aOpt[] = {
         5451  +    { "all",              SQLITE_OptMask        },
         5452  +    { "query-flattener",  SQLITE_QueryFlattener },
         5453  +    { "column-cache",     SQLITE_ColumnCache    },
         5454  +    { "index-sort",       SQLITE_IndexSort      },
         5455  +    { "index-search",     SQLITE_IndexSearch    },
         5456  +    { "index-cover",      SQLITE_IndexCover     },
         5457  +    { "groupby-order",    SQLITE_GroupByOrder   },
         5458  +    { "factor-constants", SQLITE_FactorOutConst },
         5459  +  };
         5460  +
         5461  +  if( objc!=4 ){
         5462  +    Tcl_WrongNumArgs(interp, 1, objv, "DB OPT BOOLEAN");
         5463  +    return TCL_ERROR;
         5464  +  }
         5465  +  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
         5466  +  if( Tcl_GetBooleanFromObj(interp, objv[3], &onoff) ) return TCL_ERROR;
         5467  +  zOpt = Tcl_GetString(objv[2]);
         5468  +  for(i=0; i<sizeof(aOpt)/sizeof(aOpt[0]); i++){
         5469  +    if( strcmp(zOpt, aOpt[i].zOptName)==0 ){
         5470  +      mask = aOpt[i].mask;
         5471  +      break;
         5472  +    }
         5473  +  }
         5474  +  if( onoff ) mask = ~mask;
         5475  +  if( i>=sizeof(aOpt)/sizeof(aOpt[0]) ){
         5476  +    Tcl_AppendResult(interp, "unknown optimization - should be one of:",
         5477  +                     (char*)0);
         5478  +    for(i=0; i<sizeof(aOpt)/sizeof(aOpt[0]); i++){
         5479  +      Tcl_AppendResult(interp, " ", aOpt[i].zOptName);
         5480  +    }
         5481  +    return TCL_ERROR;
         5482  +  }
         5483  +  sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, db, mask);
         5484  +  return TCL_OK;
         5485  +}
  5428   5486   
  5429   5487   /*
  5430   5488   ** Register commands with the TCL interpreter.
  5431   5489   */
  5432   5490   int Sqlitetest1_Init(Tcl_Interp *interp){
  5433   5491     extern int sqlite3_search_count;
  5434   5492     extern int sqlite3_found_count;
................................................................................
  5540   5598        { "sqlite3_enable_load_extension", test_enable_load,        0},
  5541   5599        { "sqlite3_extended_result_codes", test_extended_result_codes, 0},
  5542   5600        { "sqlite3_limit",                 test_limit,                 0},
  5543   5601   
  5544   5602        { "save_prng_state",               save_prng_state,    0 },
  5545   5603        { "restore_prng_state",            restore_prng_state, 0 },
  5546   5604        { "reset_prng_state",              reset_prng_state,   0 },
         5605  +     { "optimization_control",          optimization_control,0},
  5547   5606        { "tcl_objproc",                   runAsObjProc,       0 },
  5548   5607   
  5549   5608        /* sqlite3_column_*() API */
  5550   5609        { "sqlite3_column_count",          test_column_count  ,0 },
  5551   5610        { "sqlite3_data_count",            test_data_count    ,0 },
  5552   5611        { "sqlite3_column_type",           test_column_type   ,0 },
  5553   5612        { "sqlite3_column_blob",           test_column_blob   ,0 },

Changes to src/test_multiplex.c.

   541    541       }
   542    542       if( pSubOpen ){
   543    543         sqlite3_int64 sz;
   544    544         rc2 = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);
   545    545         if( rc2!=SQLITE_OK ){
   546    546           rc = rc2;
   547    547         }else{
          548  +        if( sz>gMultiplex.nChunkSize ){
          549  +          rc = SQLITE_IOERR_FSTAT;
          550  +        }
   548    551           *pSize += sz;
   549         -        assert(sz<=gMultiplex.nChunkSize);
   550    552         }
   551    553       }else{
   552    554         break;
   553    555       }
   554    556     }
   555    557     multiplexLeave();
   556    558     return rc;

Changes to src/test_superlock.c.

    98     98   static int superlockWalLock(
    99     99     sqlite3 *db,                    /* Database handle open on WAL database */
   100    100     SuperlockBusy *pBusy            /* Busy handler wrapper object */
   101    101   ){
   102    102     int rc;                         /* Return code */
   103    103     sqlite3_file *fd = 0;           /* Main database file handle */
   104    104     void volatile *p = 0;           /* Pointer to first page of shared memory */
   105         -  int nBusy = 0;                  /* Number of calls already made to xBusy */
   106    105   
   107    106     /* Obtain a pointer to the sqlite3_file object open on the main db file. */
   108    107     rc = sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, (void *)&fd);
   109    108     if( rc!=SQLITE_OK ) return rc;
   110    109   
   111    110     /* Obtain the "recovery" lock. Normally, this lock is only obtained by
   112    111     ** clients running database recovery.  
................................................................................
   307    306     }
   308    307   
   309    308     rc = sqlite3demo_superlock(zPath, zVfs, xBusy, &busy, &pLock);
   310    309     assert( rc==SQLITE_OK || pLock==0 );
   311    310     assert( rc!=SQLITE_OK || pLock!=0 );
   312    311   
   313    312     if( rc!=SQLITE_OK ){
          313  +    extern const char *sqlite3ErrStr(int);
   314    314       Tcl_ResetResult(interp);
   315    315       Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);
   316    316       return TCL_ERROR;
   317    317     }
   318    318   
   319    319     Tcl_CreateObjCommand(
   320    320         interp, Tcl_GetString(objv[1]), superunlock_cmd, pLock, superunlock_del

Changes to src/util.c.

   536    536     }
   537    537     if( neg ){
   538    538       v = -v;
   539    539     }
   540    540     *pValue = (int)v;
   541    541     return 1;
   542    542   }
          543  +
          544  +/*
          545  +** Return a 32-bit integer value extracted from a string.  If the
          546  +** string is not an integer, just return 0.
          547  +*/
          548  +int sqlite3Atoi(const char *z){
          549  +  int x = 0;
          550  +  if( z ) sqlite3GetInt32(z, &x);
          551  +  return x;
          552  +}
   543    553   
   544    554   /*
   545    555   ** The variable-length integer encoding is as follows:
   546    556   **
   547    557   ** KEY:
   548    558   **         A = 0xxxxxxx    7 bits of data and one flag bit
   549    559   **         B = 1xxxxxxx    7 bits of data and one flag bit

Changes to src/vdbe.c.

  1510   1510   ** Force the value in register P1 to be an integer.  If the value
  1511   1511   ** in P1 is not an integer and cannot be converted into an integer
  1512   1512   ** without data loss, then jump immediately to P2, or if P2==0
  1513   1513   ** raise an SQLITE_MISMATCH exception.
  1514   1514   */
  1515   1515   case OP_MustBeInt: {            /* jump, in1 */
  1516   1516     pIn1 = &aMem[pOp->p1];
  1517         -  memAboutToChange(p, pIn1);
  1518   1517     applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding);
  1519   1518     if( (pIn1->flags & MEM_Int)==0 ){
  1520   1519       if( pOp->p2==0 ){
  1521   1520         rc = SQLITE_MISMATCH;
  1522   1521         goto abort_due_to_error;
  1523   1522       }else{
  1524   1523         pc = pOp->p2 - 1;
................................................................................
  5783   5782   ** Write the current number of pages in database P1 to memory cell P2.
  5784   5783   */
  5785   5784   case OP_Pagecount: {            /* out2-prerelease */
  5786   5785     pOut->u.i = sqlite3BtreeLastPage(db->aDb[pOp->p1].pBt);
  5787   5786     break;
  5788   5787   }
  5789   5788   #endif
         5789  +
         5790  +
         5791  +#ifndef  SQLITE_OMIT_PAGER_PRAGMAS
         5792  +/* Opcode: MaxPgcnt P1 P2 P3 * *
         5793  +**
         5794  +** Try to set the maximum page count for database P1 to the value in P3.
         5795  +** Do not let the maximum page count fall below the current page count and
         5796  +** do not change the maximum page count value if P3==0.
         5797  +**
         5798  +** Store the maximum page count after the change in register P2.
         5799  +*/
         5800  +case OP_MaxPgcnt: {            /* out2-prerelease */
         5801  +  unsigned int newMax;
         5802  +  Btree *pBt;
         5803  +
         5804  +  pBt = db->aDb[pOp->p1].pBt;
         5805  +  newMax = 0;
         5806  +  if( pOp->p3 ){
         5807  +    newMax = sqlite3BtreeLastPage(pBt);
         5808  +    if( newMax < (unsigned)pOp->p3 ) newMax = (unsigned)pOp->p3;
         5809  +  }
         5810  +  pOut->u.i = sqlite3BtreeMaxPageCount(pBt, newMax);
         5811  +  break;
         5812  +}
         5813  +#endif
         5814  +
  5790   5815   
  5791   5816   #ifndef SQLITE_OMIT_TRACE
  5792   5817   /* Opcode: Trace * * * P4 *
  5793   5818   **
  5794   5819   ** If tracing is enabled (by the sqlite3_trace()) interface, then
  5795   5820   ** the UTF-8 string contained in P4 is emitted on the trace callback.
  5796   5821   */

Changes to src/vdbeInt.h.

    93     93   ** is allocated to store the current value of the program counter, as
    94     94   ** well as the current memory cell array and various other frame specific
    95     95   ** values stored in the Vdbe struct. When the sub-program is finished, 
    96     96   ** these values are copied back to the Vdbe from the VdbeFrame structure,
    97     97   ** restoring the state of the VM to as it was before the sub-program
    98     98   ** began executing.
    99     99   **
   100         -** Frames are stored in a linked list headed at Vdbe.pParent. Vdbe.pParent
   101         -** is the parent of the current frame, or zero if the current frame
   102         -** is the main Vdbe program.
          100  +** The memory for a VdbeFrame object is allocated and managed by a memory
          101  +** cell in the parent (calling) frame. When the memory cell is deleted or
          102  +** overwritten, the VdbeFrame object is not freed immediately. Instead, it
          103  +** is linked into the Vdbe.pDelFrame list. The contents of the Vdbe.pDelFrame
          104  +** list is deleted when the VM is reset in VdbeHalt(). The reason for doing
          105  +** this instead of deleting the VdbeFrame immediately is to avoid recursive
          106  +** calls to sqlite3VdbeMemRelease() when the memory cells belonging to the
          107  +** child frame are released.
          108  +**
          109  +** The currently executing frame is stored in Vdbe.pFrame. Vdbe.pFrame is
          110  +** set to NULL if the currently executing frame is the main program.
   103    111   */
   104    112   typedef struct VdbeFrame VdbeFrame;
   105    113   struct VdbeFrame {
   106    114     Vdbe *v;                /* VM this frame belongs to */
   107         -  int pc;                 /* Program Counter */
   108         -  Op *aOp;                /* Program instructions */
          115  +  int pc;                 /* Program Counter in parent (calling) frame */
          116  +  Op *aOp;                /* Program instructions for parent frame */
   109    117     int nOp;                /* Size of aOp array */
   110         -  Mem *aMem;              /* Array of memory cells */
          118  +  Mem *aMem;              /* Array of memory cells for parent frame */
   111    119     int nMem;               /* Number of entries in aMem */
   112         -  VdbeCursor **apCsr;     /* Element of Vdbe cursors */
          120  +  VdbeCursor **apCsr;     /* Array of Vdbe cursors for parent frame */
   113    121     u16 nCursor;            /* Number of entries in apCsr */
   114    122     void *token;            /* Copy of SubProgram.token */
   115    123     int nChildMem;          /* Number of memory cells for child frame */
   116    124     int nChildCsr;          /* Number of cursors for child frame */
   117    125     i64 lastRowid;          /* Last insert rowid (sqlite3.lastRowid) */
   118    126     int nChange;            /* Statement changes (Vdbe.nChanges)     */
   119         -  VdbeFrame *pParent;     /* Parent of this frame */
          127  +  VdbeFrame *pParent;     /* Parent of this frame, or NULL if parent is main */
   120    128   };
   121    129   
   122    130   #define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
   123    131   
   124    132   /*
   125    133   ** A value for VdbeCursor.cacheValid that means the cache is always invalid.
   126    134   */
................................................................................
   329    337     i64 nFkConstraint;      /* Number of imm. FK constraints this VM */
   330    338     i64 nStmtDefCons;       /* Number of def. constraints when stmt started */
   331    339     int iStatement;         /* Statement number (or 0 if has not opened stmt) */
   332    340   #ifdef SQLITE_DEBUG
   333    341     FILE *trace;            /* Write an execution trace here, if not NULL */
   334    342   #endif
   335    343     VdbeFrame *pFrame;      /* Parent frame */
          344  +  VdbeFrame *pDelFrame;   /* List of frame objects to free on VM reset */
   336    345     int nFrame;             /* Number of frames in pFrame list */
   337    346     u32 expmask;            /* Binding to these vars invalidates VM */
   338    347     SubProgram *pProgram;   /* Linked list of all sub-programs used by VM */
   339    348   };
   340    349   
   341    350   /*
   342    351   ** The following are allowed values for Vdbe.magic

Changes to src/vdbeaux.c.

  1533   1533           p->apCsr[i] = 0;
  1534   1534         }
  1535   1535       }
  1536   1536     }
  1537   1537     if( p->aMem ){
  1538   1538       releaseMemArray(&p->aMem[1], p->nMem);
  1539   1539     }
         1540  +  while( p->pDelFrame ){
         1541  +    VdbeFrame *pDel = p->pDelFrame;
         1542  +    p->pDelFrame = pDel->pParent;
         1543  +    sqlite3VdbeFrameDelete(pDel);
         1544  +  }
  1540   1545   }
  1541   1546   
  1542   1547   /*
  1543   1548   ** Clean up the VM after execution.
  1544   1549   **
  1545   1550   ** This routine will automatically close any cursors, lists, and/or
  1546   1551   ** sorters that were left open.  It also deletes the values of

Changes to src/vdbeblob.c.

   415    415   ** Query a blob handle for the size of the data.
   416    416   **
   417    417   ** The Incrblob.nByte field is fixed for the lifetime of the Incrblob
   418    418   ** so no mutex is required for access.
   419    419   */
   420    420   int sqlite3_blob_bytes(sqlite3_blob *pBlob){
   421    421     Incrblob *p = (Incrblob *)pBlob;
   422         -  return p ? p->nByte : 0;
          422  +  return (p && p->pStmt) ? p->nByte : 0;
   423    423   }
   424    424   
   425    425   /*
   426    426   ** Move an existing blob handle to point to a different row of the same
   427    427   ** database table.
   428    428   **
   429    429   ** If an error occurs, or if the specified row does not exist or does not
................................................................................
   453    453         sqlite3Error(db, rc, (zErr ? "%s" : 0), zErr);
   454    454         sqlite3DbFree(db, zErr);
   455    455       }
   456    456       assert( rc!=SQLITE_SCHEMA );
   457    457     }
   458    458   
   459    459     rc = sqlite3ApiExit(db, rc);
          460  +  assert( rc==SQLITE_OK || p->pStmt==0 );
   460    461     sqlite3_mutex_leave(db->mutex);
   461    462     return rc;
   462    463   }
   463    464   
   464    465   #endif /* #ifndef SQLITE_OMIT_INCRBLOB */

Changes to src/vdbemem.c.

   483    483   }
   484    484   
   485    485   /*
   486    486   ** Delete any previous value and set the value stored in *pMem to NULL.
   487    487   */
   488    488   void sqlite3VdbeMemSetNull(Mem *pMem){
   489    489     if( pMem->flags & MEM_Frame ){
   490         -    sqlite3VdbeFrameDelete(pMem->u.pFrame);
          490  +    VdbeFrame *pFrame = pMem->u.pFrame;
          491  +    pFrame->pParent = pFrame->v->pDelFrame;
          492  +    pFrame->v->pDelFrame = pFrame;
   491    493     }
   492    494     if( pMem->flags & MEM_RowSet ){
   493    495       sqlite3RowSetClear(pMem->u.pRowSet);
   494    496     }
   495    497     MemSetTypeFlag(pMem, MEM_Null);
   496    498     pMem->type = SQLITE_NULL;
   497    499   }

Changes to test/all.test.

    12     12   #
    13     13   
    14     14   set testdir [file dirname $argv0]
    15     15   source $testdir/permutations.test
    16     16   
    17     17   run_test_suite full
    18     18   
           19  +run_test_suite no_optimization 
    19     20   run_test_suite memsubsys1 
    20     21   run_test_suite memsubsys2 
    21     22   run_test_suite singlethread 
    22     23   run_test_suite multithread 
    23     24   run_test_suite onefile 
    24     25   run_test_suite utf16 
    25     26   run_test_suite exclusive

Changes to test/backcompat.test.

   266    266         SELECT * FROM t1;
   267    267       } } {I 1 II 2 III 3}
   268    268       do_test backcompat-2.1.4 { sql1 {
   269    269         SELECT * FROM t1;
   270    270       } } {I 1 II 2 III 3}
   271    271     }
   272    272   }
          273  +
          274  +#-------------------------------------------------------------------------
          275  +# Test that FTS3 tables may be read/written by different versions of 
          276  +# SQLite. 
          277  +#
          278  +set contents {
          279  +  CREATE VIRTUAL TABLE t1 USING fts3(a, b);
          280  +}
          281  +foreach {num doc} {
          282  +  one "jk zm jk eczkjblu urvysbnykk sk gnl jk ttvgf hmjf"
          283  +  two "jk bnhc jjrxpjkb mjpavjuhw fibokdry igju jk zm zm xh"
          284  +  three "wxe ogttbykvt uhzq xr iaf zf urvysbnykk aayxpmve oacaxgjoo mjpavjuhw"
          285  +  four "gazrt jk ephknonq myjp uenvbm wuvajhwqz jk zm xnxhf nvfasfh"
          286  +  five "zm aayxpmve csjqxhgj xnxhf xr jk aayxpmve xnxhf zm zm"
          287  +  six "sokcyf zm ogyavjvv jk zm fibokdry zm jk igju igju"
          288  +  seven "vgsld bvgimjik xuprtlyle jk akmikrqyt jk aayxpmve hkfoudzftq ddjj"
          289  +  eight "zm uhzq ovkyevlgv zk uenvbm csjqxhgj jk vgsld pgybs jk"
          290  +  nine  "zm agmckuiu zexh fibokdry jk uhzq bu tugflixoex xnxhf sk"
          291  +} {
          292  +  append contents "INSERT INTO t1 VALUES('$num', '$doc');"
          293  +}
          294  +do_allbackcompat_test {
          295  +  if {[code1 {set ::sqlite_options(fts3)}]
          296  +   && [code2 {set ::sqlite_options(fts3)}]
          297  +  } {
          298  +
          299  +    do_test backcompat-3.1 { sql1 $contents } {}
          300  +
          301  +    foreach {n q} {
          302  +      1    "SELECT * FROM t1 ORDER BY a, b"
          303  +      2    "SELECT rowid FROM t1 WHERE a MATCH 'five'"
          304  +      3    "SELECT * FROM t1 WHERE a MATCH 'five'"
          305  +      4    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'jk'"
          306  +      5    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'tug* OR eight'"
          307  +    } {
          308  +      do_test backcompat-3.2 [list sql1 $q] [sql2 $q]
          309  +    }
          310  +
          311  +    do_test backcompat-3.3 { sql1 {
          312  +      INSERT INTO t1 SELECT * FROM t1;
          313  +      INSERT INTO t1 SELECT * FROM t1;
          314  +      INSERT INTO t1 SELECT * FROM t1;
          315  +      INSERT INTO t1 SELECT * FROM t1;
          316  +      INSERT INTO t1 SELECT * FROM t1;
          317  +      INSERT INTO t1 SELECT * FROM t1;
          318  +      INSERT INTO t1 SELECT * FROM t1;
          319  +      INSERT INTO t1 SELECT * FROM t1;
          320  +    } } {}
          321  +
          322  +    foreach {n q} {
          323  +      1    "SELECT * FROM t1 ORDER BY a, b"
          324  +      2    "SELECT rowid FROM t1 WHERE a MATCH 'five'"
          325  +      3    "SELECT * FROM t1 WHERE a MATCH 'five'"
          326  +      4    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'jk'"
          327  +      5    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'tug* OR eight'"
          328  +    } {
          329  +      do_test backcompat-3.4 [list sql1 $q] [sql2 $q]
          330  +    }
          331  +
          332  +    set alphabet "a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4"
          333  +    for {set i 0} {$i < 900} {incr i} {
          334  +      set term "[lindex $alphabet [expr $i/30]][lindex $alphabet [expr $i%30]] "
          335  +      sql1 "INSERT INTO t1 VALUES($i, '[string repeat $term 14]')"
          336  +    }
          337  +
          338  +    foreach {n q} {
          339  +      1    "SELECT * FROM t1 ORDER BY a, b"
          340  +      2    "SELECT rowid FROM t1 WHERE a MATCH 'five'"
          341  +      3    "SELECT * FROM t1 WHERE a MATCH 'five'"
          342  +      4    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'jk'"
          343  +      5    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'tug* OR eight'"
          344  +
          345  +      6    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'aa'"
          346  +      7    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH '44'"
          347  +      8    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'a*'"
          348  +    } {
          349  +      do_test backcompat-3.5 [list sql1 $q] [sql2 $q]
          350  +    }
          351  +
          352  +    do_test backcompat-3.6 { 
          353  +      sql1 "SELECT optimize(t1) FROM t1 LIMIT 1" 
          354  +    } {{Index optimized}}
          355  +
          356  +    foreach {n q} {
          357  +      1    "SELECT * FROM t1 ORDER BY a, b"
          358  +      2    "SELECT rowid FROM t1 WHERE a MATCH 'five'"
          359  +      3    "SELECT * FROM t1 WHERE a MATCH 'five'"
          360  +      4    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'jk'"
          361  +      5    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'tug* OR eight'"
          362  +
          363  +      6    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'aa'"
          364  +      7    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH '44'"
          365  +      8    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'a*'"
          366  +    } {
          367  +      do_test backcompat-3.7 [list sql1 $q] [sql2 $q]
          368  +    }
          369  +  }
          370  +}
   273    371   
   274    372   finish_test

Changes to test/cache.test.

    47     47   # 2000 pages by default).
    48     48   #
    49     49   # This tests that once the pager-cache is initialised, it can be locked
    50     50   # and unlocked repeatedly without internally allocating any new pages.
    51     51   #
    52     52   set cache_size [pager_cache_size db]
    53     53   for {set ii 0} {$ii < 10} {incr ii} {
    54         -
    55     54     do_test cache-1.3.$ii {
    56     55       execsql {SELECT * FROM abc}
    57     56       pager_cache_size db
    58     57     } $::cache_size
           58  +}
           59  +
           60  +#-------------------------------------------------------------------------
           61  +# This block of tests checks that it is possible to set the cache_size of a
           62  +# database to a small (< 10) value. More specifically:
           63  +#
           64  +#   cache-2.1.*: Test that "PRAGMA cache_size" appears to work with small 
           65  +#                values.
           66  +#   cache-2.2.*: Test that "PRAGMA main.cache_size" appears to work with 
           67  +#                small values.
           68  +#   cache-2.3.*: Test cache_size=1 correctly spills/flushes the cache. 
           69  +#   cache-2.4.*: Test cache_size=0 correctly spills/flushes the cache. 
           70  +#
           71  +#
           72  +db_delete_and_reopen
           73  +do_execsql_test cache-2.0 {
           74  +  PRAGMA auto_vacuum=OFF;
           75  +  PRAGMA journal_mode=DELETE;
           76  +  CREATE TABLE t1(a, b);
           77  +  CREATE TABLE t2(c, d);
           78  +  INSERT INTO t1 VALUES('x', 'y');
           79  +  INSERT INTO t2 VALUES('i', 'j');
           80  +} {delete}
    59     81   
           82  +for {set i 0} {$i < 20} {incr i} {
           83  +  do_execsql_test cache-2.1.$i.1 "PRAGMA cache_size = $i"
           84  +  do_execsql_test cache-2.1.$i.2 "PRAGMA cache_size" $i
           85  +  do_execsql_test cache-2.1.$i.3 "SELECT * FROM t1" {x y}
           86  +  do_execsql_test cache-2.1.$i.4 "PRAGMA cache_size" $i
           87  +}
           88  +for {set i 0} {$i < 20} {incr i} {
           89  +  do_execsql_test cache-2.2.$i.1 "PRAGMA main.cache_size = $i"
           90  +  do_execsql_test cache-2.2.$i.2 "PRAGMA main.cache_size" $i
           91  +  do_execsql_test cache-2.2.$i.3 "SELECT * FROM t1" {x y}
           92  +  do_execsql_test cache-2.2.$i.4 "PRAGMA main.cache_size" $i
    60     93   }
    61         -sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)
           94  +
           95  +# Tests for cache_size = 1.
           96  +#
           97  +do_execsql_test cache-2.3.1 {
           98  +  PRAGMA cache_size = 1;
           99  +  BEGIN;
          100  +    INSERT INTO t1 VALUES(1, 2);
          101  +    PRAGMA lock_status;
          102  +} {main reserved temp closed}
          103  +do_test cache-2.3.2 { pager_cache_size db } 2
          104  +do_execsql_test cache-2.3.3 {
          105  +    INSERT INTO t2 VALUES(1, 2);
          106  +    PRAGMA lock_status;
          107  +} {main exclusive temp closed}
          108  +do_test cache-2.3.4 { pager_cache_size db } 2
          109  +do_execsql_test cache-2.3.5 COMMIT
          110  +do_test cache-2.3.6 { pager_cache_size db } 1
          111  +
          112  +do_execsql_test cache-2.3.7 {
          113  +  SELECT * FROM t1 UNION SELECT * FROM t2;
          114  +} {1 2 i j x y}
          115  +do_test cache-2.3.8 { pager_cache_size db } 1
          116  +
          117  +# Tests for cache_size = 0.
          118  +#
          119  +do_execsql_test cache-2.4.1 {
          120  +  PRAGMA cache_size = 0;
          121  +  BEGIN;
          122  +    INSERT INTO t1 VALUES(1, 2);
          123  +    PRAGMA lock_status;
          124  +} {main reserved temp closed}
          125  +do_test cache-2.4.2 { pager_cache_size db } 2
          126  +do_execsql_test cache-2.4.3 {
          127  +    INSERT INTO t2 VALUES(1, 2);
          128  +    PRAGMA lock_status;
          129  +} {main exclusive temp closed}
          130  +do_test cache-2.4.4 { pager_cache_size db } 2
          131  +do_execsql_test cache-2.4.5 COMMIT
          132  +
          133  +do_test cache-2.4.6 { pager_cache_size db } 0
          134  +do_execsql_test cache-2.4.7 {
          135  +  SELECT * FROM t1 UNION SELECT * FROM t2;
          136  +} {1 2 i j x y}
          137  +do_test cache-2.4.8 { pager_cache_size db } 0
    62    138   
          139  +sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)
    63    140   finish_test

Added test/e_droptrigger.test.

            1  +# 2010 November 29
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +#
           12  +# This file implements tests to verify that the "testable statements" in 
           13  +# the lang_droptrigger.html document are correct.
           14  +#
           15  +
           16  +set testdir [file dirname $argv0]
           17  +source $testdir/tester.tcl
           18  +set ::testprefix e_droptrigger
           19  +
           20  +ifcapable !trigger { finish_test ; return }
           21  +
           22  +proc do_droptrigger_tests {nm args} {
           23  +  uplevel do_select_tests [list e_createtable-$nm] $args
           24  +}
           25  +
           26  +proc list_all_triggers {{db db}} {
           27  +  set res [list]
           28  +  $db eval { PRAGMA database_list } {
           29  +    if {$name == "temp"} {
           30  +      set tbl sqlite_temp_master
           31  +    } else {
           32  +      set tbl "$name.sqlite_master"
           33  +    }
           34  +    lappend res {*}[
           35  +      db eval "SELECT '$name.' || name FROM $tbl WHERE type = 'trigger'"
           36  +    ]
           37  +  }
           38  +  set res
           39  +}
           40  +
           41  +
           42  +proc droptrigger_reopen_db {{event INSERT}} {
           43  +  db close
           44  +  forcedelete test.db test.db2
           45  +  sqlite3 db test.db
           46  +
           47  +  set ::triggers_fired [list]
           48  +  proc r {x} { lappend ::triggers_fired $x }
           49  +  db func r r
           50  +
           51  +  db eval "
           52  +    ATTACH 'test.db2' AS aux;
           53  +
           54  +    CREATE TEMP TABLE t1(a, b);
           55  +    INSERT INTO t1 VALUES('a', 'b');
           56  +    CREATE TRIGGER tr1 AFTER $event ON t1 BEGIN SELECT r('temp.tr1') ; END;
           57  +
           58  +    CREATE TABLE t2(a, b);
           59  +    INSERT INTO t2 VALUES('a', 'b');
           60  +    CREATE TRIGGER tr1 BEFORE $event ON t2 BEGIN SELECT r('main.tr1') ; END;
           61  +    CREATE TRIGGER tr2 AFTER  $event ON t2 BEGIN SELECT r('main.tr2') ; END;
           62  +
           63  +    CREATE TABLE aux.t3(a, b);
           64  +    INSERT INTO t3 VALUES('a', 'b');
           65  +    CREATE TRIGGER aux.tr1 BEFORE $event ON t3 BEGIN SELECT r('aux.tr1') ; END;
           66  +    CREATE TRIGGER aux.tr2 AFTER  $event ON t3 BEGIN SELECT r('aux.tr2') ; END;
           67  +    CREATE TRIGGER aux.tr3 AFTER  $event ON t3 BEGIN SELECT r('aux.tr3') ; END;
           68  +  "
           69  +}
           70  +
           71  +
           72  +# EVIDENCE-OF: R-52650-16855 -- syntax diagram drop-trigger-stmt
           73  +#
           74  +do_droptrigger_tests 1.1 -repair {
           75  +  droptrigger_reopen_db
           76  +} -tclquery {
           77  +  list_all_triggers 
           78  +} {
           79  +  1   "DROP TRIGGER main.tr1"            
           80  +      {main.tr2 temp.tr1 aux.tr1 aux.tr2 aux.tr3}
           81  +  2   "DROP TRIGGER IF EXISTS main.tr1"  
           82  +      {main.tr2 temp.tr1 aux.tr1 aux.tr2 aux.tr3}
           83  +  3   "DROP TRIGGER tr1"                 
           84  +      {main.tr1 main.tr2 aux.tr1 aux.tr2 aux.tr3}
           85  +  4   "DROP TRIGGER IF EXISTS tr1"       
           86  +      {main.tr1 main.tr2 aux.tr1 aux.tr2 aux.tr3}
           87  +
           88  +  5   "DROP TRIGGER aux.tr1"             
           89  +      {main.tr1 main.tr2 temp.tr1 aux.tr2 aux.tr3}
           90  +  6   "DROP TRIGGER IF EXISTS aux.tr1"   
           91  +      {main.tr1 main.tr2 temp.tr1 aux.tr2 aux.tr3}
           92  +
           93  +  7   "DROP TRIGGER IF EXISTS aux.xxx"   
           94  +      {main.tr1 main.tr2 temp.tr1 aux.tr1 aux.tr2 aux.tr3}
           95  +  8   "DROP TRIGGER IF EXISTS aux.xxx"   
           96  +      {main.tr1 main.tr2 temp.tr1 aux.tr1 aux.tr2 aux.tr3}
           97  +}
           98  +
           99  +# EVIDENCE-OF: R-61172-15671 The DROP TRIGGER statement removes a
          100  +# trigger created by the CREATE TRIGGER statement.
          101  +#
          102  +foreach {tn tbl droptrigger before after} {
          103  +  1   t1  "DROP TRIGGER tr1" {temp.tr1}                {}
          104  +  2   t2  "DROP TRIGGER tr1" {main.tr1 main.tr2}       {main.tr1 main.tr2}
          105  +  3   t3  "DROP TRIGGER tr1" {aux.tr1 aux.tr3 aux.tr2} {aux.tr1 aux.tr3 aux.tr2}
          106  +
          107  +  4   t1  "DROP TRIGGER tr2" {temp.tr1}                {temp.tr1}
          108  +  5   t2  "DROP TRIGGER tr2" {main.tr1 main.tr2}       {main.tr1}
          109  +  6   t3  "DROP TRIGGER tr2" {aux.tr1 aux.tr3 aux.tr2} {aux.tr1 aux.tr3 aux.tr2}
          110  +
          111  +  7   t1  "DROP TRIGGER tr3" {temp.tr1}                {temp.tr1}
          112  +  8   t2  "DROP TRIGGER tr3" {main.tr1 main.tr2}       {main.tr1 main.tr2}
          113  +  9   t3  "DROP TRIGGER tr3" {aux.tr1 aux.tr3 aux.tr2} {aux.tr1 aux.tr2}
          114  +} {
          115  +
          116  +  do_test 2.$tn.1 {
          117  +    droptrigger_reopen_db
          118  +    execsql " INSERT INTO $tbl VALUES('1', '2') "
          119  +    set ::triggers_fired
          120  +  } $before
          121  +
          122  +  do_test 2.$tn.2 {
          123  +    droptrigger_reopen_db
          124  +    execsql $droptrigger
          125  +    execsql " INSERT INTO $tbl VALUES('1', '2') "
          126  +    set ::triggers_fired
          127  +  } $after
          128  +}
          129  +
          130  +# EVIDENCE-OF: R-50239-29811 Once removed, the trigger definition is no
          131  +# longer present in the sqlite_master (or sqlite_temp_master) table and
          132  +# is not fired by any subsequent INSERT, UPDATE or DELETE statements.
          133  +#
          134  +#   Test cases e_droptrigger-1.* test the first part of this statement
          135  +#   (that dropped triggers do not appear in the schema table), and tests
          136  +#   droptrigger-2.* test that dropped triggers are not fired by INSERT
          137  +#   statements. The following tests verify that they are not fired by
          138  +#   UPDATE or DELETE statements.
          139  +#
          140  +foreach {tn tbl droptrigger before after} {
          141  +  1   t1  "DROP TRIGGER tr1" {temp.tr1}                {}
          142  +  2   t2  "DROP TRIGGER tr1" {main.tr1 main.tr2}       {main.tr1 main.tr2}
          143  +  3   t3  "DROP TRIGGER tr1" {aux.tr1 aux.tr3 aux.tr2} {aux.tr1 aux.tr3 aux.tr2}
          144  +
          145  +  4   t1  "DROP TRIGGER tr2" {temp.tr1}                {temp.tr1}
          146  +  5   t2  "DROP TRIGGER tr2" {main.tr1 main.tr2}       {main.tr1}
          147  +  6   t3  "DROP TRIGGER tr2" {aux.tr1 aux.tr3 aux.tr2} {aux.tr1 aux.tr3 aux.tr2}
          148  +
          149  +  7   t1  "DROP TRIGGER tr3" {temp.tr1}                {temp.tr1}
          150  +  8   t2  "DROP TRIGGER tr3" {main.tr1 main.tr2}       {main.tr1 main.tr2}
          151  +  9   t3  "DROP TRIGGER tr3" {aux.tr1 aux.tr3 aux.tr2} {aux.tr1 aux.tr2}
          152  +} {
          153  +
          154  +  do_test 3.1.$tn.1 {
          155  +    droptrigger_reopen_db UPDATE
          156  +    execsql "UPDATE $tbl SET a = 'abc'"
          157  +    set ::triggers_fired
          158  +  } $before
          159  +
          160  +  do_test 3.1.$tn.2 {
          161  +    droptrigger_reopen_db UPDATE
          162  +    execsql $droptrigger
          163  +    execsql "UPDATE $tbl SET a = 'abc'"
          164  +    set ::triggers_fired
          165  +  } $after
          166  +}
          167  +foreach {tn tbl droptrigger before after} {
          168  +  1   t1  "DROP TRIGGER tr1" {temp.tr1}                {}
          169  +  2   t2  "DROP TRIGGER tr1" {main.tr1 main.tr2}       {main.tr1 main.tr2}
          170  +  3   t3  "DROP TRIGGER tr1" {aux.tr1 aux.tr3 aux.tr2} {aux.tr1 aux.tr3 aux.tr2}
          171  +
          172  +  4   t1  "DROP TRIGGER tr2" {temp.tr1}                {temp.tr1}
          173  +  5   t2  "DROP TRIGGER tr2" {main.tr1 main.tr2}       {main.tr1}
          174  +  6   t3  "DROP TRIGGER tr2" {aux.tr1 aux.tr3 aux.tr2} {aux.tr1 aux.tr3 aux.tr2}
          175  +
          176  +  7   t1  "DROP TRIGGER tr3" {temp.tr1}                {temp.tr1}
          177  +  8   t2  "DROP TRIGGER tr3" {main.tr1 main.tr2}       {main.tr1 main.tr2}
          178  +  9   t3  "DROP TRIGGER tr3" {aux.tr1 aux.tr3 aux.tr2} {aux.tr1 aux.tr2}
          179  +} {
          180  +
          181  +  do_test 3.2.$tn.1 {
          182  +    droptrigger_reopen_db DELETE
          183  +    execsql "DELETE FROM $tbl"
          184  +    set ::triggers_fired
          185  +  } $before
          186  +
          187  +  do_test 3.2.$tn.2 {
          188  +    droptrigger_reopen_db DELETE
          189  +    execsql $droptrigger
          190  +    execsql "DELETE FROM $tbl"
          191  +    set ::triggers_fired
          192  +  } $after
          193  +}
          194  +
          195  +# EVIDENCE-OF: R-37808-62273 Note that triggers are automatically
          196  +# dropped when the associated table is dropped.
          197  +#
          198  +do_test 4.1 {
          199  +  droptrigger_reopen_db
          200  +  list_all_triggers
          201  +} {main.tr1 main.tr2 temp.tr1 aux.tr1 aux.tr2 aux.tr3}
          202  +do_test 4.2 {
          203  +  droptrigger_reopen_db
          204  +  execsql "DROP TABLE t1"
          205  +  list_all_triggers
          206  +} {main.tr1 main.tr2 aux.tr1 aux.tr2 aux.tr3}
          207  +do_test 4.3 {
          208  +  droptrigger_reopen_db
          209  +  execsql "DROP TABLE t1"
          210  +  list_all_triggers
          211  +} {main.tr1 main.tr2 aux.tr1 aux.tr2 aux.tr3}
          212  +do_test 4.4 {
          213  +  droptrigger_reopen_db
          214  +  execsql "DROP TABLE t1"
          215  +  list_all_triggers
          216  +} {main.tr1 main.tr2 aux.tr1 aux.tr2 aux.tr3}
          217  +
          218  +finish_test

Added test/e_dropview.test.

            1  +# 2010 November 30
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +#
           12  +# This file implements tests to verify that the "testable statements" in 
           13  +# the lang_dropview.html document are correct.
           14  +#
           15  +
           16  +set testdir [file dirname $argv0]
           17  +source $testdir/tester.tcl
           18  +set ::testprefix e_dropview
           19  +
           20  +proc dropview_reopen_db {} {
           21  +  db close
           22  +  forcedelete test.db test.db2
           23  +  sqlite3 db test.db
           24  +
           25  +  db eval {
           26  +    ATTACH 'test.db2' AS aux;
           27  +    CREATE TABLE t1(a, b); 
           28  +    INSERT INTO t1 VALUES('a main', 'b main');
           29  +    CREATE VIEW v1 AS SELECT * FROM t1;
           30  +    CREATE VIEW v2 AS SELECT * FROM t1;
           31  +
           32  +    CREATE TEMP TABLE t1(a, b);
           33  +    INSERT INTO temp.t1 VALUES('a temp', 'b temp');
           34  +    CREATE VIEW temp.v1 AS SELECT * FROM t1;
           35  +
           36  +    CREATE TABLE aux.t1(a, b);
           37  +    INSERT INTO aux.t1 VALUES('a aux', 'b aux');
           38  +    CREATE VIEW aux.v1 AS SELECT * FROM t1;
           39  +    CREATE VIEW aux.v2 AS SELECT * FROM t1;
           40  +    CREATE VIEW aux.v3 AS SELECT * FROM t1;
           41  +  }
           42  +}
           43  +
           44  +proc list_all_views {{db db}} {
           45  +  set res [list]
           46  +  $db eval { PRAGMA database_list } {
           47  +    set tbl "$name.sqlite_master"
           48  +    if {$name == "temp"} { set tbl sqlite_temp_master }
           49  +
           50  +    set sql "SELECT '$name.' || name FROM $tbl WHERE type = 'view'"
           51  +    lappend res {*}[$db eval $sql]
           52  +  }
           53  +  set res
           54  +}
           55  +
           56  +proc list_all_data {{db db}} {
           57  +  set res [list]
           58  +  $db eval { PRAGMA database_list } {
           59  +    set tbl "$name.sqlite_master"
           60  +    if {$name == "temp"} { set tbl sqlite_temp_master }
           61  +
           62  +    db eval "SELECT '$name.' || name AS x FROM $tbl WHERE type = 'table'" {
           63  +      lappend res [list $x [db eval "SELECT * FROM $x"]]
           64  +    }
           65  +  }
           66  +  set res
           67  +}
           68  +
           69  +proc do_dropview_tests {nm args} {
           70  +  uplevel do_select_tests $nm $args
           71  +}
           72  +
           73  +# EVIDENCE-OF: R-21739-51207 -- syntax diagram drop-view-stmt
           74  +#
           75  +# All paths in the syntax diagram for DROP VIEW are tested by tests 1.*.
           76  +#
           77  +do_dropview_tests 1 -repair {
           78  +  dropview_reopen_db
           79  +} -tclquery {
           80  +  list_all_views
           81  +} {
           82  +  1   "DROP VIEW v1"                  {main.v1 main.v2 aux.v1 aux.v2 aux.v3}
           83  +  2   "DROP VIEW v2"                  {main.v1 temp.v1 aux.v1 aux.v2 aux.v3}
           84  +  3   "DROP VIEW main.v1"             {main.v2 temp.v1 aux.v1 aux.v2 aux.v3}
           85  +  4   "DROP VIEW main.v2"             {main.v1 temp.v1 aux.v1 aux.v2 aux.v3}
           86  +  5   "DROP VIEW IF EXISTS v1"        {main.v1 main.v2 aux.v1 aux.v2 aux.v3}
           87  +  6   "DROP VIEW IF EXISTS v2"        {main.v1 temp.v1 aux.v1 aux.v2 aux.v3}
           88  +  7   "DROP VIEW IF EXISTS main.v1"   {main.v2 temp.v1 aux.v1 aux.v2 aux.v3}
           89  +  8   "DROP VIEW IF EXISTS main.v2"   {main.v1 temp.v1 aux.v1 aux.v2 aux.v3}
           90  +}
           91  +
           92  +# EVIDENCE-OF: R-27002-52307 The DROP VIEW statement removes a view
           93  +# created by the CREATE VIEW statement.
           94  +#
           95  +dropview_reopen_db
           96  +do_execsql_test 2.1 {
           97  +  CREATE VIEW "new view" AS SELECT * FROM t1 AS x, t1 AS y;
           98  +  SELECT * FROM "new view";
           99  +} {{a main} {b main} {a main} {b main}}
          100  +do_execsql_test 2.2 {;
          101  +  SELECT * FROM sqlite_master WHERE name = 'new view';
          102  +} {
          103  +  view {new view} {new view} 0 
          104  +  {CREATE VIEW "new view" AS SELECT * FROM t1 AS x, t1 AS y}
          105  +}
          106  +do_execsql_test 2.3 {
          107  +  DROP VIEW "new view";
          108  +  SELECT * FROM sqlite_master WHERE name = 'new view';
          109  +} {}
          110  +do_catchsql_test 2.4 {
          111  +  SELECT * FROM "new view"
          112  +} {1 {no such table: new view}}
          113  +
          114  +# EVIDENCE-OF: R-00359-41639 The view definition is removed from the
          115  +# database schema, but no actual data in the underlying base tables is
          116  +# modified.
          117  +#
          118  +#     For each view in the database, check that it can be queried. Then drop
          119  +#     it. Check that it can no longer be queried and is no longer listed
          120  +#     in any schema table. Then check that the contents of the db tables have 
          121  +#     not changed
          122  +#
          123  +set databasedata [list_all_data]
          124  +
          125  +do_execsql_test  3.1.0 { SELECT * FROM temp.v1 } {{a temp} {b temp}}
          126  +do_execsql_test  3.1.1 { DROP VIEW temp.v1 } {}
          127  +do_catchsql_test 3.1.2 { SELECT * FROM temp.v1 } {1 {no such table: temp.v1}}
          128  +do_test          3.1.3 { list_all_views } {main.v1 main.v2 aux.v1 aux.v2 aux.v3}
          129  +do_test          3.1.4 { list_all_data  } $databasedata
          130  +
          131  +do_execsql_test  3.2.0 { SELECT * FROM v1 } {{a main} {b main}}
          132  +do_execsql_test  3.2.1 { DROP VIEW v1 } {}
          133  +do_catchsql_test 3.2.2 { SELECT * FROM main.v1 } {1 {no such table: main.v1}}
          134  +do_test          3.2.3 { list_all_views } {main.v2 aux.v1 aux.v2 aux.v3}
          135  +do_test          3.2.4 { list_all_data  } $databasedata
          136  +
          137  +do_execsql_test  3.3.0 { SELECT * FROM v2 } {{a main} {b main}}
          138  +do_execsql_test  3.3.1 { DROP VIEW v2 } {}
          139  +do_catchsql_test 3.3.2 { SELECT * FROM main.v2 } {1 {no such table: main.v2}}
          140  +do_test          3.3.3 { list_all_views } {aux.v1 aux.v2 aux.v3}
          141  +do_test          3.3.4 { list_all_data  } $databasedata
          142  +
          143  +do_execsql_test  3.4.0 { SELECT * FROM v1 } {{a aux} {b aux}}
          144  +do_execsql_test  3.4.1 { DROP VIEW v1 } {}
          145  +do_catchsql_test 3.4.2 { SELECT * FROM v1 } {1 {no such table: v1}}
          146  +do_test          3.4.3 { list_all_views } {aux.v2 aux.v3}
          147  +do_test          3.4.4 { list_all_data  } $databasedata
          148  +
          149  +do_execsql_test  3.4.0 { SELECT * FROM aux.v2 } {{a aux} {b aux}}
          150  +do_execsql_test  3.4.1 { DROP VIEW aux.v2 } {}
          151  +do_catchsql_test 3.4.2 { SELECT * FROM aux.v2 } {1 {no such table: aux.v2}}
          152  +do_test          3.4.3 { list_all_views } {aux.v3}
          153  +do_test          3.4.4 { list_all_data  } $databasedata
          154  +
          155  +do_execsql_test  3.5.0 { SELECT * FROM v3 } {{a aux} {b aux}}
          156  +do_execsql_test  3.5.1 { DROP VIEW v3 } {}
          157  +do_catchsql_test 3.5.2 { SELECT * FROM v3 } {1 {no such table: v3}}
          158  +do_test          3.5.3 { list_all_views } {}
          159  +do_test          3.5.4 { list_all_data  } $databasedata
          160  +
          161  +# EVIDENCE-OF: R-25558-37487 If the specified view cannot be found and
          162  +# the IF EXISTS clause is not present, it is an error.
          163  +#
          164  +do_dropview_tests 4 -repair {
          165  +  dropview_reopen_db 
          166  +} -errorformat {
          167  +  no such view: %s
          168  +} {
          169  +  1   "DROP VIEW xx"                  xx
          170  +  2   "DROP VIEW main.xx"             main.xx
          171  +  3   "DROP VIEW temp.v2"             temp.v2
          172  +}
          173  +
          174  +# EVIDENCE-OF: R-07490-32536 If the specified view cannot be found and
          175  +# an IF EXISTS clause is present in the DROP VIEW statement, then the
          176  +# statement is a no-op.
          177  +#
          178  +do_dropview_tests 5 -repair {
          179  +  dropview_reopen_db
          180  +} -tclquery {
          181  +  list_all_views
          182  +  expr {[list_all_views] == "main.v1 main.v2 temp.v1 aux.v1 aux.v2 aux.v3"}
          183  +} {
          184  +  1    "DROP VIEW IF EXISTS xx"       1
          185  +  2    "DROP VIEW IF EXISTS main.xx"  1
          186  +  3    "DROP VIEW IF EXISTS temp.v2"  1
          187  +}
          188  +
          189  +
          190  +
          191  +
          192  +finish_test

Added test/e_resolve.test.

            1  +# 2010 November 30
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +#
           12  +# This file implements tests to verify that the "testable statements" in 
           13  +# the lang_naming.html document are correct.
           14  +#
           15  +
           16  +set testdir [file dirname $argv0]
           17  +source $testdir/tester.tcl
           18  +set ::testprefix e_resolve
           19  +
           20  +# An example database schema for testing name resolution:
           21  +#
           22  +set schema {
           23  +  ATTACH 'test.db2' AS at1;
           24  +  ATTACH 'test.db3' AS at2;
           25  +
           26  +  CREATE TABLE   temp.n1(x, y); INSERT INTO temp.n1 VALUES('temp', 'n1');
           27  +  CREATE TRIGGER temp.n3 AFTER INSERT ON n1 BEGIN SELECT 1; END;
           28  +  CREATE INDEX   temp.n4 ON n1(x, y);
           29  +
           30  +  CREATE TABLE   main.n1(x, y); INSERT INTO main.n1 VALUES('main', 'n1');
           31  +  CREATE TABLE   main.n2(x, y); INSERT INTO main.n2 VALUES('main', 'n2');
           32  +  CREATE INDEX   main.n3 ON n2(y, x);
           33  +  CREATE TRIGGER main.n4 BEFORE INSERT ON n2 BEGIN SELECT 1; END;
           34  +
           35  +  CREATE TABLE   at1.n1(x, y);  INSERT INTO at1.n1 VALUES('at1', 'n1');
           36  +  CREATE TABLE   at1.n2(x, y);  INSERT INTO at1.n2 VALUES('at1', 'n2');
           37  +  CREATE TABLE   at1.n3(x, y);  INSERT INTO at1.n3 VALUES('at1', 'n3');
           38  +
           39  +  CREATE TABLE   at2.n1(x, y);  INSERT INTO at2.n1 VALUES('at2', 'n1');
           40  +  CREATE TABLE   at2.n2(x, y);  INSERT INTO at2.n2 VALUES('at2', 'n2');
           41  +  CREATE TABLE   at2.n3(x, y);  INSERT INTO at2.n3 VALUES('at2', 'n3');
           42  +  CREATE TABLE   at2.n4(x, y);  INSERT INTO at2.n4 VALUES('at2', 'n4');
           43  +  CREATE TRIGGER at2.n4 BEFORE INSERT ON n4 BEGIN SELECT 1; END;
           44  +}
           45  +
           46  +proc resolve_reopen_db {} {
           47  +  db close
           48  +  forcedelete test.db test.db2 test.db3
           49  +  sqlite3 db test.db
           50  +  db eval $::schema
           51  +}
           52  +
           53  +
           54  +
           55  +# EVIDENCE-OF: R-33528-20612 If no database is specified as part of the
           56  +# object reference, then SQLite searches the main, temp and all attached
           57  +# databases for an object with a matching name. The temp database is
           58  +# searched first, followed by the main database, followed all attached
           59  +# databases in the order that they were attached. The reference resolves
           60  +# to the first match found.
           61  +#
           62  +resolve_reopen_db
           63  +do_execsql_test 1.1 { SELECT * FROM n1 } {temp n1}
           64  +do_execsql_test 1.2 { SELECT * FROM n2 } {main n2}
           65  +do_execsql_test 1.3 { SELECT * FROM n3 } {at1  n3}
           66  +do_execsql_test 1.4 { SELECT * FROM n4 } {at2  n4}
           67  +
           68  +# EVIDENCE-OF: R-54577-28142 If a database name is specified as part of
           69  +# an object reference, it must be either "main", or "temp" or the name
           70  +# of an attached database.
           71  +#
           72  +#   Or else it is a "no such table: xxx" error.
           73  +#
           74  +resolve_reopen_db
           75  +do_execsql_test 2.1.1 { SELECT * FROM main.n1 } {main n1}
           76  +do_execsql_test 2.1.2 { SELECT * FROM temp.n1 } {temp n1}
           77  +do_execsql_test 2.1.3 { SELECT * FROM at1.n1 } {at1 n1}
           78  +do_execsql_test 2.1.4 { SELECT * FROM at2.n1 } {at2 n1}
           79  +
           80  +do_catchsql_test 2.2 { SELECT * FROM xxx.n1 } {1 {no such table: xxx.n1}}
           81  +
           82  +# EVIDENCE-OF: R-26223-47623 Like other SQL identifiers, database names
           83  +# are case-insensitive.
           84  +#
           85  +resolve_reopen_db
           86  +do_execsql_test 3.1 { SELECT * FROM MAIN.n1 } {main n1}
           87  +do_execsql_test 3.2 { SELECT * FROM tEmP.n1 } {temp n1}
           88  +do_execsql_test 3.3 { SELECT * FROM aT1.n1 } {at1 n1}
           89  +do_execsql_test 3.4 { SELECT * FROM At2.n1 } {at2 n1}
           90  +
           91  +# EVIDENCE-OF: R-15639-28392 If a database name is specified, then only
           92  +# the named database is searched for the named object.
           93  +#
           94  +do_catchsql_test 4.1 { SELECT * FROM temp.n2 } {1 {no such table: temp.n2}}
           95  +do_catchsql_test 4.2 { SELECT * FROM main.n2 } {0 {main n2}}
           96  +do_catchsql_test 4.3 { SELECT * FROM at1.n2 }  {0 {at1 n2}}
           97  +do_catchsql_test 4.4 { SELECT * FROM at2.n2 }  {0 {at2 n2}}
           98  +
           99  +# EVIDENCE-OF: R-08951-19801 When searching database schemas for a named
          100  +# object, objects of types that cannot be used in the context of the
          101  +# reference are always ignored.
          102  +#
          103  +#   In this case, "types that cannot be used" are triggers and indexes.
          104  +#   The temp and main databases both contain triggers and indexes named
          105  +#   "n3" and "n4". Database "at2" contains a trigger called "n4". And yet:
          106  +#
          107  +do_execsql_test 5.1 { SELECT * FROM n3 } {at1  n3}
          108  +do_execsql_test 5.2 { SELECT * FROM n4 } {at2  n4}
          109  +
          110  +#-------------------------------------------------------------------------
          111  +# EVIDENCE-OF: R-37286-42536 
          112  +#
          113  +db close
          114  +forcedelete test.db file.db
          115  +sqlite3 db test.db
          116  +do_execsql_test 6.1 {
          117  +  ATTACH 'file.db' AS aux;
          118  +  CREATE TABLE t1(x, y);
          119  +  CREATE TEMP TABLE t1(x, y);
          120  +  CREATE TABLE aux.t1(x, y);
          121  +}
          122  +
          123  +do_execsql_test  6.2.0 { DROP TABLE t1 }
          124  +do_catchsql_test 6.2.1 { SELECT * FROM temp.t1 } {1 {no such table: temp.t1}}
          125  +do_catchsql_test 6.2.2 { SELECT * FROM main.t1 } {0 {}}
          126  +do_catchsql_test 6.2.3 { SELECT * FROM aux.t1  } {0 {}}
          127  +
          128  +do_execsql_test  6.3.0 { DROP TABLE t1 }
          129  +do_catchsql_test 6.3.1 { SELECT * FROM main.t1 } {1 {no such table: main.t1}}
          130  +do_catchsql_test 6.3.3 { SELECT * FROM aux.t1  } {0 {}}
          131  +
          132  +do_execsql_test  6.4.0 { DROP TABLE t1 }
          133  +do_catchsql_test 6.4.1 { SELECT * FROM aux.t1 } {1 {no such table: aux.t1}}
          134  +
          135  +finish_test

Changes to test/fts3aa.test.

   192    192   } {{four five}}
   193    193   do_test fts3aa-6.2 {
   194    194     execsql {INSERT INTO t1(rowid, content) VALUES(-1, 'three four')}
   195    195   } {}
   196    196   do_test fts3aa-6.3 {
   197    197     execsql {SELECT content FROM t1 WHERE rowid = -1}
   198    198   } {{three four}}
   199         -breakpoint
   200    199   do_test fts3aa-6.4 {
   201    200     execsql {SELECT rowid FROM t1 WHERE t1 MATCH 'four'}
   202    201   } {-1 0 8 9 10 11 12 13 14 15 24 25 26 27 28 29 30 31}
          202  +
          203  +# Test creation of FTS3 and FTS4 tables with columns that contain
          204  +# an "=" character.
          205  +#
          206  +do_execsql_test fts3aa-7.1 {
          207  +  CREATE VIRTUAL TABLE t2 USING fts3(xyz=abc);
          208  +  SELECT xyz FROM t2;
          209  +} {}
          210  +do_catchsql_test fts3aa-7.2 {
          211  +  CREATE VIRTUAL TABLE t3 USING fts4(xyz=abc);
          212  +} {1 {unrecognized parameter: xyz=abc}}
          213  +do_catchsql_test fts3aa-7.3 {
          214  +  CREATE VIRTUAL TABLE t3 USING fts4(xyz = abc);
          215  +} {1 {unrecognized parameter: xyz = abc}}
          216  +
          217  +do_execsql_test fts3aa-7.4 {
          218  +  CREATE VIRTUAL TABLE t3 USING fts3(tokenize=simple, tokenize=simple);
          219  +  SELECT tokenize FROM t3;
          220  +} {}
          221  +do_catchsql_test fts3aa-7.5 {
          222  +  CREATE VIRTUAL TABLE t4 USING fts4(tokenize=simple, tokenize=simple);
          223  +} {1 {unrecognized parameter: tokenize=simple}}
          224  +
   203    225   
   204    226   finish_test
          227  +

Changes to test/fts3defer2.test.

    49     49   } {2}
    50     50   
    51     51   do_execsql_test 1.2.1 {
    52     52     SELECT content FROM t1 WHERE t1 MATCH 'f (e NEAR/2 a)';
    53     53   } {{a b c d e f a x y}}
    54     54   
    55     55   do_execsql_test 1.2.2 {
    56         -  SELECT snippet(t1, '[', ']'), offsets(t1), mit(matchinfo(t1))
           56  +  SELECT snippet(t1, '[', ']'), offsets(t1), mit(matchinfo(t1, 'pcxnal'))
    57     57     FROM t1 WHERE t1 MATCH 'f (e NEAR/2 a)';
    58     58   } [list                              \
    59     59      {a b c d [e] [f] [a] x y}         \
    60     60      {0 1 8 1 0 0 10 1 0 2 12 1}       \
    61     61      [list 3 1   1 1 1   1 8 8   1 8 8   8 5001 9]
    62     62   ]
    63     63   
    64     64   do_execsql_test 1.2.3 {
    65         -  SELECT snippet(t1, '[', ']'), offsets(t1), mit(matchinfo(t1))
           65  +  SELECT snippet(t1, '[', ']'), offsets(t1), mit(matchinfo(t1, 'pcxnal'))
    66     66     FROM t1 WHERE t1 MATCH 'f (e NEAR/3 a)';
    67     67   } [list                                 \
    68     68      {[a] b c d [e] [f] [a] x y}          \
    69     69      {0 2 0 1 0 1 8 1 0 0 10 1 0 2 12 1}  \
    70     70      [list 3 1   1 1 1   1 8 8   2 8 8   8 5001 9]
    71     71   ]
    72     72   
................................................................................
    87     87     1 {}
    88     88     2 { INSERT INTO t2(t2) VALUES('optimize') }
    89     89     3 { UPDATE t2_segments SET block = zeroblob(length(block)) 
    90     90         WHERE length(block)>10000;
    91     91     }
    92     92   } {
    93     93     execsql $sql
           94  +
    94     95     do_execsql_test 2.2.$tn {
    95         -    SELECT mit(matchinfo(t2)) FROM t2 WHERE t2 MATCH 'a b';
           96  +    SELECT mit(matchinfo(t2, 'pcxnal')) FROM t2 WHERE t2 MATCH 'a b';
    96     97     } [list                                          \
    97     98       [list 2 1  1 54 54  1 3 3  54 372 7]        \
    98     99       [list 2 1  1 54 54  1 3 3  54 372 7]        \
    99    100     ]
   100    101   }
   101    102   
   102    103   do_execsql_test 2.3.1 {
................................................................................
   120    121     2 { INSERT INTO t3(t3) VALUES('optimize') }
   121    122     3 { UPDATE t3_segments SET block = zeroblob(length(block)) 
   122    123         WHERE length(block)>10000;
   123    124     }
   124    125   } {
   125    126     execsql $sql
   126    127     do_execsql_test 2.4.$tn {
   127         -    SELECT docid, mit(matchinfo(t3)) FROM t3 WHERE t3 MATCH '"a b c"';
          128  +    SELECT docid, mit(matchinfo(t3, 'pcxnal')) FROM t3 WHERE t3 MATCH '"a b c"';
   128    129     } {1 {1 1 1 4 4 11 912 6} 3 {1 1 1 4 4 11 912 6}}
   129    130   }
   130    131   
   131    132   
   132    133   finish_test
   133    134   

Changes to test/fts3fault.test.

    13     13   set testdir [file dirname $argv0]
    14     14   source $testdir/tester.tcl
    15     15   
    16     16   set ::testprefix fts3fault
    17     17   
    18     18   # If SQLITE_ENABLE_FTS3 is not defined, omit this file.
    19     19   ifcapable !fts3 { finish_test ; return }
           20  +
           21  +if 1 {
    20     22   
    21     23   # Test error handling in the sqlite3Fts3Init() function. This is the 
    22     24   # function that registers the FTS3 module and various support functions
    23     25   # with SQLite.
    24     26   #
    25     27   do_faultsim_test 1 -body { 
    26     28     sqlite3 db test.db 
................................................................................
   150    152     faultsim_delete_and_reopen
   151    153   } -body {
   152    154     execsql { CREATE VIRTUAL TABLE t1 USING fts4(a, b, matchnfo=fts3) }
   153    155   } -test {
   154    156     faultsim_test_result {1 {unrecognized parameter: matchnfo=fts3}} \
   155    157                          {1 {vtable constructor failed: t1}}
   156    158   }
          159  +
          160  +}
          161  +
          162  +proc mit {blob} {
          163  +  set scan(littleEndian) i*
          164  +  set scan(bigEndian) I*
          165  +  binary scan $blob $scan($::tcl_platform(byteOrder)) r
          166  +  return $r
          167  +}
          168  +
          169  +do_test 8.0 {
          170  +  faultsim_delete_and_reopen
          171  +  execsql { CREATE VIRTUAL TABLE t8 USING fts4 }
          172  +  execsql "INSERT INTO t8 VALUES('a b c')"
          173  +  execsql "INSERT INTO t8 VALUES('b b b')"
          174  +  execsql "INSERT INTO t8 VALUES('[string repeat {c } 50000]')"
          175  +  execsql "INSERT INTO t8 VALUES('d d d')"
          176  +  execsql "INSERT INTO t8 VALUES('e e e')"
          177  +  execsql "INSERT INTO t8(t8) VALUES('optimize')"
          178  +  faultsim_save_and_close
          179  +} {}
          180  +
          181  +do_faultsim_test 8.1 -prep { 
          182  +  faultsim_restore_and_reopen
          183  +  db func mit mit
          184  +} -body {
          185  +  execsql { SELECT mit(matchinfo(t8, 'x')) FROM t8 WHERE t8 MATCH 'a b c' }
          186  +} -test {
          187  +  faultsim_test_result {0 {{1 1 1 1 4 2 1 5 5}}}
          188  +}
          189  +do_faultsim_test 8.2 -faults oom-t* -prep { 
          190  +  faultsim_restore_and_reopen
          191  +  db func mit mit
          192  +} -body {
          193  +  execsql { SELECT mit(matchinfo(t8, 's')) FROM t8 WHERE t8 MATCH 'a b c' }
          194  +} -test {
          195  +  faultsim_test_result {0 3}
          196  +}
          197  +do_faultsim_test 8.3 -prep { 
          198  +  faultsim_restore_and_reopen
          199  +  db func mit mit
          200  +} -body {
          201  +  execsql { SELECT mit(matchinfo(t8, 'a')) FROM t8 WHERE t8 MATCH 'a b c' }
          202  +} -test {
          203  +  faultsim_test_result {0 10002}
          204  +}
          205  +do_faultsim_test 8.4 -prep { 
          206  +  faultsim_restore_and_reopen
          207  +  db func mit mit
          208  +} -body {
          209  +  execsql { SELECT mit(matchinfo(t8, 'l')) FROM t8 WHERE t8 MATCH 'a b c' }
          210  +} -test {
          211  +  faultsim_test_result {0 3}
          212  +}
          213  +
          214  +do_test 9.0 {
          215  +  faultsim_delete_and_reopen
          216  +  execsql {
          217  +    CREATE VIRTUAL TABLE t9 USING fts4(tokenize=porter);
          218  +    INSERT INTO t9 VALUES(
          219  +      'this record is used toooooooooooooooooooooooooooooooooooooo try to'
          220  +    );
          221  +    SELECT offsets(t9) FROM t9 WHERE t9 MATCH 'to*';
          222  +  }
          223  +  faultsim_save_and_close
          224  +} {}
          225  +do_faultsim_test 9.1 -prep {
          226  +  faultsim_restore_and_reopen
          227  +} -body {
          228  +  execsql { SELECT offsets(t9) FROM t9 WHERE t9 MATCH 'to*' }
          229  +} -test {
          230  +  faultsim_test_result {0 {{0 0 20 39 0 0 64 2}}}
          231  +}
   157    232   
   158    233   finish_test

Changes to test/fts3matchinfo.test.

    37     37     INSERT INTO t1(content) VALUES('I wandered lonely as a cloud');
    38     38     INSERT INTO t1(content) VALUES('That floats on high o''er vales and hills,');
    39     39     INSERT INTO t1(content) VALUES('When all at once I saw a crowd,');
    40     40     INSERT INTO t1(content) VALUES('A host, of golden daffodils,');
    41     41     SELECT mit(matchinfo(t1)) FROM t1 WHERE t1 MATCH 'I';
    42     42   } {{1 1 1 2 2} {1 1 1 2 2}}
    43     43   
    44         -# Now create an FTS4 table that does not specify matchinfo=fts3. The 
    45         -# %_docsize table is created in this case and the array of integers returned
    46         -# by matchinfo() includes the extra data.
           44  +# Now create an FTS4 table that does not specify matchinfo=fts3.
    47     45   #
    48     46   do_execsql_test 1.2 {
    49     47     CREATE VIRTUAL TABLE t2 USING fts4;
    50     48     INSERT INTO t2 SELECT * FROM t1;
    51     49     SELECT mit(matchinfo(t2)) FROM t2 WHERE t2 MATCH 'I';
    52         -} {{1 1 1 2 2 4 7 6} {1 1 1 2 2 4 7 8}}
           50  +} {{1 1 1 2 2} {1 1 1 2 2}}
    53     51   
    54     52   # Test some syntax-error handling.
    55     53   #
    56     54   do_catchsql_test 2.0 {
    57     55     CREATE VIRTUAL TABLE x1 USING fts4(matchinfo=fs3);
    58     56   } {1 {unrecognized matchinfo: fs3}}
    59     57   do_catchsql_test 2.1 {
................................................................................
    63     61   # Check that with fts3, the "=" character is permitted in column definitions.
    64     62   #
    65     63   do_execsql_test 3.1 {
    66     64     CREATE VIRTUAL TABLE t3 USING fts3(mtchinfo=fts3);
    67     65     INSERT INTO t3(mtchinfo) VALUES('Beside the lake, beneath the trees');
    68     66     SELECT mtchinfo FROM t3;
    69     67   } {{Beside the lake, beneath the trees}}
           68  +
           69  +do_execsql_test 3.2 {
           70  +  CREATE VIRTUAL TABLE xx USING FTS4;
           71  +  SELECT * FROM xx WHERE xx MATCH 'abc';
           72  +  SELECT * FROM xx WHERE xx MATCH 'a b c';
           73  +}
           74  +
           75  +
           76  +#--------------------------------------------------------------------------
           77  +# Proc [do_matchinfo_test] is used to test the FTSX matchinfo() function.
           78  +#
           79  +# The first argument - $tn - is a test identifier. This may be either a
           80  +# full identifier (i.e. "fts3matchinfo-1.1") or, if global var $testprefix
           81  +# is set, just the numeric component (i.e. "1.1").
           82  +#
           83  +# The second argument is the name of an FTSX table. The third is the 
           84  +# full text of a WHERE/MATCH expression to query the table for 
           85  +# (i.e. "t1 MATCH 'abc'"). The final argument - $results - should be a
           86  +# key-value list (serialized array) with matchinfo() format specifiers
           87  +# as keys, and the results of executing the statement:
           88  +#
           89  +#   SELECT matchinfo($tbl, '$key') FROM $tbl WHERE $expr
           90  +#
           91  +# For example:
           92  +#
           93  +#   CREATE VIRTUAL TABLE t1 USING fts4;
           94  +#   INSERT INTO t1 VALUES('abc');
           95  +#   INSERT INTO t1 VALUES('def');
           96  +#   INSERT INTO t1 VALUES('abc abc');
           97  +#
           98  +#   do_matchinfo_test 1.1 t1 "t1 MATCH 'abc'" {
           99  +#     n {3 3}
          100  +#     p {1 1}
          101  +#     c {1 1}
          102  +#     x {{1 3 2} {2 3 2}}
          103  +#   }
          104  +#
          105  +# If the $results list contains keys mapped to "-" instead of a matchinfo()
          106  +# result, then this command computes the expected results based on other
          107  +# mappings to test the matchinfo() function. For example, the command above
          108  +# could be changed to:
          109  +#
          110  +#   do_matchinfo_test 1.1 t1 "t1 MATCH 'abc'" {
          111  +#     n {3 3} p {1 1} c {1 1} x {{1 3 2} {2 3 2}}
          112  +#     pcx -
          113  +#   }
          114  +#
          115  +# And this command would compute the expected results for matchinfo(t1, 'pcx')
          116  +# based on the results of matchinfo(t1, 'p'), matchinfo(t1, 'c') and 
          117  +# matchinfo(t1, 'x') in order to test 'pcx'.
          118  +#
          119  +proc do_matchinfo_test {tn tbl expr results} {
          120  +
          121  +  foreach {fmt res} $results {
          122  +    if {$res == "-"} continue
          123  +    set resarray($fmt) $res
          124  +  }
          125  +
          126  +  set nRow 0
          127  +  foreach {fmt res} [array get resarray] {
          128  +    if {[llength $res]>$nRow} { set nRow [llength $res] }
          129  +  }
          130  +
          131  +  # Construct expected results for any formats for which the caller 
          132  +  # supplied result is "-".
          133  +  #
          134  +  foreach {fmt res} $results {
          135  +    if {$res == "-"} {
          136  +      set res [list]
          137  +      for {set iRow 0} {$iRow<$nRow} {incr iRow} {
          138  +        set rowres [list]
          139  +        foreach c [split $fmt ""] {
          140  +          set rowres [concat $rowres [lindex $resarray($c) $iRow]]
          141  +        }
          142  +        lappend res $rowres
          143  +      }
          144  +      set resarray($fmt) $res
          145  +    }
          146  +  }
          147  +
          148  +  # Test each matchinfo() request individually.
          149  +  #
          150  +  foreach {fmt res} [array get resarray] {
          151  +    set sql "SELECT mit(matchinfo($tbl, '$fmt')) FROM $tbl WHERE $expr"
          152  +    do_execsql_test $tn.$fmt $sql [normalize2 $res]
          153  +  }
          154  +
          155  +  # Test them all executed together (multiple invocations of matchinfo()).
          156  +  #
          157  +  set exprlist [list]
          158  +  foreach {format res} [array get resarray] {
          159  +    lappend exprlist "mit(matchinfo($tbl, '$format'))"
          160  +  }
          161  +  set allres [list]
          162  +  for {set iRow 0} {$iRow<$nRow} {incr iRow} {
          163  +    foreach {format res} [array get resarray] {
          164  +      lappend allres [lindex $res $iRow]
          165  +    }
          166  +  }
          167  +  set sql "SELECT [join $exprlist ,] FROM $tbl WHERE $expr"
          168  +  do_execsql_test $tn.multi $sql [normalize2 $allres]
          169  +}
          170  +proc normalize2 {list_of_lists} {
          171  +  set res [list]
          172  +  foreach elem $list_of_lists {
          173  +    lappend res [list {*}$elem]
          174  +  }
          175  +  return $res
          176  +}
          177  +
          178  +
          179  +do_execsql_test 4.1.0 {
          180  +  CREATE VIRTUAL TABLE t4 USING fts4(x, y);
          181  +  INSERT INTO t4 VALUES('a b c d e', 'f g h i j');
          182  +  INSERT INTO t4 VALUES('f g h i j', 'a b c d e');
          183  +}
          184  +
          185  +do_matchinfo_test 4.1.1 t4 {t4 MATCH 'a b c'} {
          186  +  p {3 3}
          187  +  c {2 2}
          188  +  x {
          189  +    {1 1 1   0 1 1   1 1 1   0 1 1   1 1 1   0 1 1}
          190  +    {0 1 1   1 1 1   0 1 1   1 1 1   0 1 1   1 1 1}
          191  +  }
          192  +  n {2 2}
          193  +  l {{5 5} {5 5}}
          194  +  a {{5 5} {5 5}}
          195  +
          196  +  s {{3 0} {0 3}}
          197  +
          198  +  xxxxxxxxxxxxxxxxxx - pcx - xpc - ccc - pppxpcpcx - laxnpc -
          199  +  xpxsscplax -
          200  +}
          201  +
          202  +do_matchinfo_test 4.1.2 t4 {t4 MATCH '"g h i"'} {
          203  +  p {1 1}
          204  +  c {2 2}
          205  +  x {
          206  +    {0 1 1   1 1 1}
          207  +    {1 1 1   0 1 1}
          208  +  }
          209  +  n {2 2}
          210  +  l {{5 5} {5 5}}
          211  +  a {{5 5} {5 5}}
          212  +
          213  +  s {{0 1} {1 0}}
          214  +
          215  +  xxxxxxxxxxxxxxxxxx - pcx - xpc - ccc - pppxpcpcx - laxnpc -
          216  +  sxsxs -
          217  +}
          218  +
          219  +do_matchinfo_test 4.1.3 t4 {t4 MATCH 'a b'}     { s {{2 0} {0 2}} }
          220  +do_matchinfo_test 4.1.4 t4 {t4 MATCH '"a b" c'} { s {{2 0} {0 2}} }
          221  +do_matchinfo_test 4.1.5 t4 {t4 MATCH 'a "b c"'} { s {{2 0} {0 2}} }
          222  +do_matchinfo_test 4.1.6 t4 {t4 MATCH 'd d'}     { s {{1 0} {0 1}} }
          223  +
          224  +do_execsql_test 4.2.0 {
          225  +  CREATE VIRTUAL TABLE t5 USING fts4;
          226  +  INSERT INTO t5 VALUES('a a a a a');
          227  +  INSERT INTO t5 VALUES('a b a b a');
          228  +  INSERT INTO t5 VALUES('c b c b c');
          229  +  INSERT INTO t5 VALUES('x x x x x');
          230  +}
          231  +do_matchinfo_test 4.2.1 t5 {t5 MATCH 'a a'}         { 
          232  +  x {{5 8 2   5 8 2} {3 8 2   3 8 2}}
          233  +  s {2 1} 
          234  +}
          235  +do_matchinfo_test 4.2.2 t5 {t5 MATCH 'a b'}         { s {2} }
          236  +do_matchinfo_test 4.2.3 t5 {t5 MATCH 'a b a'}       { s {3} }
          237  +do_matchinfo_test 4.2.4 t5 {t5 MATCH 'a a a'}       { s {3 1} }
          238  +do_matchinfo_test 4.2.5 t5 {t5 MATCH '"a b" "a b"'} { s {2} }
          239  +do_matchinfo_test 4.2.6 t5 {t5 MATCH 'a OR b'}      { s {1 2 1} }
          240  +
          241  +do_execsql_test 4.3.0 "INSERT INTO t5 VALUES('x y [string repeat {b } 50000]')";
          242  +
          243  +do_matchinfo_test 4.3.1 t5 {t5 MATCH 'a a'} { 
          244  +  x {{5 8 2   5 5 5} {3 8 2   3 5 5}}
          245  +  s {2 1} 
          246  +}
          247  +
          248  +do_matchinfo_test 4.3.2 t5 {t5 MATCH 'a b'}         { s {2} }
          249  +do_matchinfo_test 4.3.3 t5 {t5 MATCH 'a b a'}       { s {3} }
          250  +do_matchinfo_test 4.3.4 t5 {t5 MATCH 'a a a'}       { s {3 1} }
          251  +do_matchinfo_test 4.3.5 t5 {t5 MATCH '"a b" "a b"'} { s {2} }
          252  +do_matchinfo_test 4.3.6 t5 {t5 MATCH 'a OR b'}      { s {1 2 1 1} }
          253  +
          254  +do_execsql_test 4.4.0 {
          255  +  INSERT INTO t5(t5) VALUES('optimize');
          256  +  UPDATE t5_segments 
          257  +  SET block = zeroblob(length(block)) 
          258  +  WHERE length(block)>10000;
          259  +}
          260  +
          261  +do_matchinfo_test 4.4.2 t5 {t5 MATCH 'a b'}         { s {2} }
          262  +do_matchinfo_test 4.4.1 t5 {t5 MATCH 'a a'}         { s {2 1} }
          263  +do_matchinfo_test 4.4.2 t5 {t5 MATCH 'a b'}         { s {2} }
          264  +do_matchinfo_test 4.4.3 t5 {t5 MATCH 'a b a'}       { s {3} }
          265  +do_matchinfo_test 4.4.4 t5 {t5 MATCH 'a a a'}       { s {3 1} }
          266  +do_matchinfo_test 4.4.5 t5 {t5 MATCH '"a b" "a b"'} { s {2} }
          267  +
          268  +do_execsql_test 4.5.0 {
          269  +  CREATE VIRTUAL TABLE t6 USING fts4(a, b, c);
          270  +  INSERT INTO t6 VALUES('a', 'b', 'c');
          271  +}
          272  +do_matchinfo_test 4.5.1 t6 {t6 MATCH 'a b c'}       { s {{1 1 1}} }
          273  +
          274  +
          275  +#-------------------------------------------------------------------------
          276  +# Check the following restrictions:
          277  +#
          278  +#   + Matchinfo flags 'a', 'l' and 'n' can only be used with fts4, not fts3.
          279  +#   + Matchinfo flag 'l' cannot be used with matchinfo=fts3.
          280  +#
          281  +do_execsql_test 5.1 {
          282  +  CREATE VIRTUAL TABLE t7 USING fts3(a, b);
          283  +  INSERT INTO t7 VALUES('u v w', 'x y z');
          284  +
          285  +  CREATE VIRTUAL TABLE t8 USING fts4(a, b, matchinfo=fts3);
          286  +  INSERT INTO t8 VALUES('u v w', 'x y z');
          287  +}
          288  +
          289  +do_catchsql_test 5.2.1 { 
          290  +  SELECT matchinfo(t7, 'a') FROM t7 WHERE t7 MATCH 'x y'
          291  +} {1 {unrecognized matchinfo request: a}}
          292  +do_catchsql_test 5.2.2 { 
          293  +  SELECT matchinfo(t7, 'l') FROM t7 WHERE t7 MATCH 'x y'
          294  +} {1 {unrecognized matchinfo request: l}}
          295  +do_catchsql_test 5.2.3 { 
          296  +  SELECT matchinfo(t7, 'n') FROM t7 WHERE t7 MATCH 'x y'
          297  +} {1 {unrecognized matchinfo request: n}}
          298  +
          299  +do_catchsql_test 5.3.1 { 
          300  +  SELECT matchinfo(t8, 'l') FROM t8 WHERE t8 MATCH 'x y'
          301  +} {1 {unrecognized matchinfo request: l}}
          302  +
          303  +#-------------------------------------------------------------------------
          304  +# Test that the offsets() function handles corruption in the %_content
          305  +# table correctly.
          306  +#
          307  +do_execsql_test 6.1 {
          308  +  CREATE VIRTUAL TABLE t9 USING fts4;
          309  +  INSERT INTO t9 VALUES(
          310  +    'this record is used to try to dectect corruption'
          311  +  );
          312  +  SELECT offsets(t9) FROM t9 WHERE t9 MATCH 'to';
          313  +} {{0 0 20 2 0 0 27 2}}
          314  +
          315  +do_catchsql_test 6.2 {
          316  +  UPDATE t9_content SET c0content = 'this record is used to'; 
          317  +  SELECT offsets(t9) FROM t9 WHERE t9 MATCH 'to';
          318  +} {1 {database disk image is malformed}}
          319  +
          320  +#-------------------------------------------------------------------------
          321  +# Test the outcome of matchinfo() when used within a query that does not
          322  +# use the full-text index (i.e. lookup by rowid or full-table scan).
          323  +#
          324  +do_execsql_test 7.1 {
          325  +  CREATE VIRTUAL TABLE t10 USING fts4;
          326  +  INSERT INTO t10 VALUES('first record');
          327  +  INSERT INTO t10 VALUES('second record');
          328  +}
          329  +do_execsql_test 7.2 {
          330  +  SELECT typeof(matchinfo(t10)), length(matchinfo(t10)) FROM t10;
          331  +} {blob 0 blob 0}
          332  +do_execsql_test 7.3 {
          333  +  SELECT typeof(matchinfo(t10)), length(matchinfo(t10)) FROM t10 WHERE docid=1;
          334  +} {blob 0}
          335  +do_execsql_test 7.4 {
          336  +  SELECT typeof(matchinfo(t10)), length(matchinfo(t10)) 
          337  +  FROM t10 WHERE t10 MATCH 'record'
          338  +} {blob 20 blob 20}
          339  +
    70    340   
    71    341   finish_test
          342  +

Changes to test/fts3query.test.

   148    148     CREATE VIRTUAL TABLE t2 USING FTS4;
   149    149     INSERT INTO t2 VALUES('it was the first time in history');
   150    150   }
   151    151   do_select_tests 5.2 -errorformat {
   152    152     wrong number of arguments to function %s()
   153    153   } {
   154    154     1 "SELECT matchinfo() FROM t2 WHERE t2 MATCH 'history'"       matchinfo
   155         -  2 "SELECT matchinfo(t2, t2) FROM t2 WHERE t2 MATCH 'history'" matchinfo
   156         -
   157    155     3 "SELECT snippet(t2, 1, 2, 3, 4, 5, 6) FROM t2 WHERE t2 MATCH 'history'" 
   158    156       snippet
   159    157   }
   160    158   do_select_tests 5.3 -errorformat {
   161    159     illegal first argument to %s
   162    160   } {
   163    161     1 "SELECT matchinfo(content) FROM t2 WHERE t2 MATCH 'history'" matchinfo
................................................................................
   170    168     illegal first argument to %s
   171    169   } {
   172    170     1 "SELECT matchinfo(content) FROM t2 WHERE t2 MATCH 'history'" matchinfo
   173    171     2 "SELECT offsets(content) FROM t2 WHERE t2 MATCH 'history'"   offsets
   174    172     3 "SELECT snippet(content) FROM t2 WHERE t2 MATCH 'history'"   snippet
   175    173     4 "SELECT optimize(content) FROM t2 WHERE t2 MATCH 'history'"  optimize
   176    174   }
          175  +do_catchsql_test 5.5.1 {
          176  +  SELECT matchinfo(t2, 'abc') FROM t2 WHERE t2 MATCH 'history'
          177  +} {1 {unrecognized matchinfo request: b}}
          178  +
   177    179   do_execsql_test 5.5 { DROP TABLE t2 }
          180  +
   178    181   
   179    182   # Test the snippet() function with 1 to 6 arguments.
   180    183   # 
   181    184   do_execsql_test 6.1 {
   182    185     CREATE VIRTUAL TABLE t3 USING FTS4(a, b);
   183    186     INSERT INTO t3 VALUES('no gestures', 'another intriguing discovery by observing the hand gestures (called beats) people make while speaking. Research has shown that such gestures do more than add visual emphasis to our words (many people gesture while they''re on the telephone, for example); it seems they actually help our brains find words');
   184    187   }

Changes to test/fts3rnd.test.

   301    301         set iInsert [expr {int(rand()*1000000)}]
   302    302       }
   303    303       execsql BEGIN
   304    304         insert_row $iInsert
   305    305         update_row $iUpdate
   306    306         delete_row $iDelete
   307    307       if {0==($iTest%2)} { execsql COMMIT }
          308  +
          309  +    if {0==($iTest%2)} { 
          310  +      do_test fts3rnd-1.$nodesize.$iTest.0 { fts3_integrity_check t1 } ok 
          311  +    }
   308    312   
   309    313       # Pick 10 terms from the vocabulary. Check that the results of querying
   310    314       # the database for the set of documents containing each of these terms
   311    315       # is the same as the result obtained by scanning the contents of the Tcl 
   312    316       # array for each term.
   313    317       #
   314    318       for {set i 0} {$i < 10} {incr i} {
................................................................................
   375    379   
   376    380       # A 3-way NEAR query with terms as the arguments.
   377    381       #
   378    382       for {set i 0} {$i < $nRep} {incr i} {
   379    383         set terms [list [random_term] [random_term] [random_term]]
   380    384         set nNear 11
   381    385         set match [join $terms " NEAR/$nNear "]
   382         -      set fts3 [execsql { SELECT docid FROM t1 WHERE t1 MATCH $match }]
   383    386         do_select_test fts3rnd-1.$nodesize.$iTest.7.$i {
   384    387           SELECT docid FROM t1 WHERE t1 MATCH $match
   385    388         } [simple_near $terms $nNear]
   386    389       }
   387    390       
   388    391       # Set operations on simple term queries.
   389    392       #

Changes to test/incrblob3.test.

    88     88     } {1 SQLITE_ABORT}
    89     89     do_test incrblob3-2.2.$tn.4 {
    90     90       list [catch {sqlite3_blob_read $::blob 0 10} msg] $msg
    91     91     } {1 SQLITE_ABORT}
    92     92     do_test incrblob3-2.2.$tn.5 {
    93     93       list [catch {sqlite3_blob_write $::blob 0 "abcd"} msg] $msg
    94     94     } {1 SQLITE_ABORT}
           95  +  do_test incrblob3-2.2.$tn.6 {
           96  +    sqlite3_blob_bytes $::blob
           97  +  } {0}
    95     98   
    96         -  do_test incrblob3-2.2.$tn.4 { close $::blob } {}
           99  +  do_test incrblob3-2.2.$tn.7 { close $::blob } {}
    97    100   }
    98    101   
    99    102   # Test that passing NULL to sqlite3_blob_XXX() APIs returns SQLITE_MISUSE.
   100    103   #
   101    104   #   incrblob3-3.1: sqlite3_blob_reopen()
   102    105   #   incrblob3-3.2: sqlite3_blob_read()
   103    106   #   incrblob3-3.3: sqlite3_blob_write()

Changes to test/lock_common.tcl.

    12     12   # code in this file allows testfixture to control another process (or
    13     13   # processes) to test locking.
    14     14   #
    15     15   
    16     16   proc do_multiclient_test {varname script} {
    17     17   
    18     18     foreach code [list {
           19  +    if {[info exists ::G(valgrind)]} { db close ; continue }
    19     20       set ::code2_chan [launch_testfixture]
    20     21       set ::code3_chan [launch_testfixture]
    21     22       proc code2 {tcl} { testfixture $::code2_chan $tcl }
    22     23       proc code3 {tcl} { testfixture $::code3_chan $tcl }
    23     24       set tn 1
    24     25     } {
    25     26       proc code2 {tcl} { uplevel #0 $tcl }

Changes to test/malloc_common.tcl.

   130    130     }
   131    131   
   132    132     set testspec [list -prep $O(-prep) -body $O(-body) -test $O(-test)]
   133    133     foreach f [lsort -unique $faultlist] {
   134    134       eval do_one_faultsim_test "$name-$f" $FAULTSIM($f) $testspec
   135    135     }
   136    136   }
          137  +
   137    138   
   138    139   #-------------------------------------------------------------------------
   139    140   # Procedures to save and restore the current file-system state:
   140    141   #
   141    142   #   faultsim_save
   142    143   #   faultsim_restore
   143    144   #   faultsim_save_and_close
   144    145   #   faultsim_restore_and_reopen
   145    146   #   faultsim_delete_and_reopen
   146    147   #
   147         -proc faultsim_save {} {
   148         -  foreach f [glob -nocomplain sv_test.db*] { forcedelete $f }
   149         -  foreach f [glob -nocomplain test.db*] {
   150         -    set f2 "sv_$f"
   151         -    file copy -force $f $f2
   152         -  }
          148  +proc faultsim_save {args} { uplevel db_save $args }
          149  +proc faultsim_save_and_close {args} { uplevel db_save_and_close $args }
          150  +proc faultsim_restore {args} { uplevel db_restore $args }
          151  +proc faultsim_restore_and_reopen {args} { 
          152  +  uplevel db_restore_and_reopen $args 
          153  +  sqlite3_extended_result_codes db 1
          154  +  sqlite3_db_config_lookaside db 0 0 0
   153    155   }
   154         -proc faultsim_save_and_close {} {
   155         -  faultsim_save
   156         -  catch { db close }
   157         -  return ""
   158         -}
   159         -proc faultsim_restore {} {
   160         -  foreach f [glob -nocomplain test.db*] { forcedelete $f }
   161         -  foreach f2 [glob -nocomplain sv_test.db*] {
   162         -    set f [string range $f2 3 end]
   163         -    file copy -force $f2 $f
   164         -  }
   165         -}
   166         -proc faultsim_restore_and_reopen {{dbfile test.db}} {
   167         -  catch { db close }
   168         -  faultsim_restore
   169         -  sqlite3 db $dbfile
          156  +proc faultsim_delete_and_reopen {args} {
          157  +  uplevel db_delete_and_reopen $args 
   170    158     sqlite3_extended_result_codes db 1
   171    159     sqlite3_db_config_lookaside db 0 0 0
   172    160   }
   173    161   
   174    162   proc faultsim_integrity_check {{db db}} {
   175    163     set ic [$db eval { PRAGMA integrity_check }]
   176    164     if {$ic != "ok"} { error "Integrity check: $ic" }
   177    165   }
   178    166   
   179         -proc faultsim_delete_and_reopen {{file test.db}} {
   180         -  catch { db close }
   181         -  foreach f [glob -nocomplain test.db*] { file delete -force $f }
   182         -  sqlite3 db $file
   183         -}
   184         -
   185    167   
   186    168   # The following procs are used as [do_one_faultsim_test] callbacks when 
   187    169   # injecting OOM faults into test cases.
   188    170   #
   189    171   proc oom_injectstart {nRepeat iFail} {
   190    172     sqlite3_memdebug_fail [expr $iFail-1] -repeat $nRepeat
   191    173   }

Changes to test/misc7.test.

   255    255   
   256    256   db close
   257    257   file delete -force test.db
   258    258   file delete -force test.db-journal
   259    259   sqlite3 db test.db
   260    260   
   261    261   ifcapable explain {
   262         -  do_test misc7-14.1 {
   263         -    execsql {
   264         -      CREATE TABLE abc(a PRIMARY KEY, b, c);
   265         -    }
   266         -    execsql {
   267         -      EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 WHERE rowid = 1;
   268         -    }
   269         -  } {0 0 {TABLE abc AS t2 USING PRIMARY KEY}}
   270         -  do_test misc7-14.2 {
   271         -    execsql {
   272         -      EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 WHERE a = 1;
   273         -    }
   274         -  } {0 0 {TABLE abc AS t2 WITH INDEX sqlite_autoindex_abc_1}}
   275         -  do_test misc7-14.3 {
   276         -    execsql {
   277         -      EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 ORDER BY a;
   278         -    }
   279         -  } {0 0 {TABLE abc AS t2 WITH INDEX sqlite_autoindex_abc_1 ORDER BY}}
          262  +  do_execsql_test misc7-14.1 {
          263  +    CREATE TABLE abc(a PRIMARY KEY, b, c);
          264  +    EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 WHERE rowid = 1;
          265  +  } {
          266  +    0 0 0 {SEARCH TABLE abc AS t2 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}
          267  +  }
          268  +  do_execsql_test misc7-14.2 {
          269  +    EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 WHERE a = 1;
          270  +  } {0 0 0 
          271  +     {SEARCH TABLE abc AS t2 USING INDEX sqlite_autoindex_abc_1 (a=?) (~1 rows)}
          272  +  }
          273  +  do_execsql_test misc7-14.3 {
          274  +    EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 ORDER BY a;
          275  +  } {0 0 0 
          276  +     {SCAN TABLE abc AS t2 USING INDEX sqlite_autoindex_abc_1 (~1000000 rows)}
          277  +  }
   280    278   }
   281    279   
   282    280   db close
   283    281   file delete -force test.db
   284    282   file delete -force test.db-journal
   285    283   sqlite3 db test.db
   286    284   

Changes to test/multiplex.test.

    50     50       forcedelete [multiplex_name $name-journal $i]
    51     51       forcedelete [multiplex_name $name-wal $i]
    52     52     }
    53     53   }
    54     54   
    55     55   db close
    56     56   
           57  +multiplex_delete test.db
           58  +multiplex_delete test2.db
           59  +
    57     60   #-------------------------------------------------------------------------
    58     61   #   multiplex-1.1.*: Test initialize and shutdown.
    59     62   
    60     63   do_test multiplex-1.1 { sqlite3_multiplex_initialize nosuchvfs 1 } {SQLITE_ERROR}
    61     64   do_test multiplex-1.2 { sqlite3_multiplex_initialize "" 1 }        {SQLITE_OK}
    62     65   do_test multiplex-1.3 { sqlite3_multiplex_initialize "" 1 }        {SQLITE_MISUSE}
    63     66   do_test multiplex-1.4 { sqlite3_multiplex_shutdown }               {SQLITE_OK}
................................................................................
   119    122   
   120    123   do_test multiplex-2.2.1 {
   121    124     execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
   122    125   } {}
   123    126   do_test multiplex-2.2.3 { file size [multiplex_name test.db 0] } {6144}
   124    127   
   125    128   do_test multiplex-2.3.1 {
   126         -  sqlite3 db2 bak.db
          129  +  sqlite3 db2 test2.db
   127    130     db2 close
   128    131   } {}
   129    132   
   130    133   do_test multiplex-2.4.1 {
   131    134     sqlite3_multiplex_shutdown
   132    135   } {SQLITE_MISUSE}
   133    136   do_test multiplex-2.4.2 {
................................................................................
   443    446   
   444    447   do_faultsim_test multiplex-5.5 -prep {
   445    448     catch { sqlite3_multiplex_shutdown }
   446    449   } -body {
   447    450     sqlite3_multiplex_initialize "" 1
   448    451     multiplex_set 32768 16
   449    452   }
          453  +
          454  +# test that mismatch filesize is detected
          455  +#
          456  +# Do not run this test if $::G(perm:presql) is set. If it is set, then the
          457  +# expected IO error will occur within the Tcl [sqlite3] wrapper, not within
          458  +# the first SQL statement executed below. This breaks the test case.
          459  +#
          460  +if {0==[info exists ::G(perm:presql)] || $::G(perm:presql) == ""} {
          461  +  set all_journal_modes {delete persist truncate memory off}
          462  +  foreach jmode $all_journal_modes {
          463  +    do_test multiplex-5.6.1.$jmode {
          464  +      sqlite3_multiplex_shutdown
          465  +      multiplex_delete test.db
          466  +      sqlite3 db test.db
          467  +      db eval {
          468  +        PRAGMA page_size = 1024;
          469  +        PRAGMA auto_vacuum = off;
          470  +      }
          471  +      db eval "PRAGMA journal_mode = $jmode;"
          472  +    } $jmode
          473  +    do_test multiplex-5.6.2.$jmode {
          474  +      execsql {
          475  +        CREATE TABLE t1(a, b);
          476  +        INSERT INTO t1 VALUES(1, randomblob(1100));
          477  +        INSERT INTO t1 VALUES(2, randomblob(1100));
          478  +        INSERT INTO t1 VALUES(3, randomblob(1100));
          479  +        INSERT INTO t1 VALUES(4, randomblob(1100));
          480  +        INSERT INTO t1 VALUES(5, randomblob(1100));
          481  +      }
          482  +      db close
          483  +      sqlite3_multiplex_initialize "" 1
          484  +      multiplex_set 4096 16
          485  +      sqlite3 db test.db
          486  +    } {}
          487  +    do_test multiplex-5.6.3.$jmode {
          488  +      catchsql {
          489  +        INSERT INTO t1 VALUES(6, randomblob(1100));
          490  +      }
          491  +    } {1 {disk I/O error}}
          492  +    do_test multiplex-5.6.4.$jmode {
          493  +      db close
          494  +    } {}
          495  +  }
          496  +}
   450    497   
   451    498   catch { sqlite3_multiplex_shutdown }
   452    499   finish_test

Changes to test/pager1.test.

  1058   1058   } {13}
  1059   1059   do_execsql_test pager1-6.8 {
  1060   1060       INSERT INTO t11 VALUES(3, 4);
  1061   1061       PRAGMA max_page_count = 10;
  1062   1062   } {11}
  1063   1063   do_execsql_test pager1-6.9 { COMMIT } {}
  1064   1064   
  1065         -do_execsql_test pager1-6.10 { PRAGMA max_page_count = 10 } {10}
         1065  +do_execsql_test pager1-6.10 { PRAGMA max_page_count = 10 } {11}
  1066   1066   do_execsql_test pager1-6.11 { SELECT * FROM t11 }          {1 2 3 4}
  1067   1067   do_execsql_test pager1-6.12 { PRAGMA max_page_count }      {11}
  1068   1068   
  1069   1069   
  1070   1070   #-------------------------------------------------------------------------
  1071   1071   # The following tests work with "PRAGMA journal_mode=TRUNCATE" and
  1072   1072   # "PRAGMA locking_mode=EXCLUSIVE".

Changes to test/permutations.test.

    21     21   #
    22     22   #       -description TITLE                  (default "")
    23     23   #       -initialize  SCRIPT                 (default "")
    24     24   #       -shutdown    SCRIPT                 (default "")
    25     25   #       -presql      SQL                    (default "")
    26     26   #       -files       LIST-OF-FILES          (default $::ALLTESTS)
    27     27   #       -prefix      NAME                   (default "$::NAME.")
           28  +#       -dbconfig    SCRIPT                 (default "")
    28     29   #
    29     30   proc test_suite {name args} {
    30     31   
    31     32     set default(-shutdown)    ""
    32     33     set default(-initialize)  ""
    33     34     set default(-presql)      ""
    34     35     set default(-description) "no description supplied (fixme)"
    35     36     set default(-files)       ""
    36     37     set default(-prefix)      "${name}."
           38  +  set default(-dbconfig)    ""
    37     39   
    38     40     array set options [array get default]
    39     41     if {[llength $args]%2} {
    40     42       error "uneven number of options/switches passed to test_suite"
    41     43     }
    42     44     foreach {k v} $args {
    43     45       set o [array names options ${k}*]
................................................................................
    44     46       if {[llength $o]>1}  { error "ambiguous option: $k" }
    45     47       if {[llength $o]==0} { error "unknown option: $k" }
    46     48       set options([lindex $o 0]) $v
    47     49     }
    48     50   
    49     51     set     ::testspec($name) [array get options]
    50     52     lappend ::testsuitelist $name
    51         -
    52     53   }
    53     54   
    54     55   #-------------------------------------------------------------------------
    55     56   # test_set ARGS...
    56     57   #
    57     58   proc test_set {args} {
    58     59     set isExclude 0
................................................................................
   132    133   test_suite "veryquick" -prefix "" -description {
   133    134     "Very" quick test suite. Runs in less than 5 minutes on a workstation. 
   134    135     This test suite is the same as the "quick" tests, except that some files
   135    136     that test malloc and IO errors are omitted.
   136    137   } -files [
   137    138     test_set $allquicktests -exclude *malloc* *ioerr* *fault*
   138    139   ]
          140  +
          141  +test_suite "valgrind" -prefix "" -description {
          142  +  Run the "veryquick" test suite with a couple of multi-process tests (that
          143  +  fail under valgrind) omitted.
          144  +} -files [
          145  +  test_set $allquicktests -exclude *malloc* *ioerr* *fault*
          146  +] -initialize {
          147  +  set ::G(valgrind) 1
          148  +} -shutdown {
          149  +  unset -nocomplain ::G(valgrind)
          150  +}
   139    151   
   140    152   test_suite "quick" -prefix "" -description {
   141    153     Quick test suite. Runs in around 10 minutes on a workstation.
   142    154   } -files [
   143    155     test_set $allquicktests
   144    156   ]
   145    157   
................................................................................
   742    754     fts3am.test  fts3an.test  fts3ao.test  fts3b.test
   743    755     fts3c.test   fts3d.test   fts3e.test   fts3query.test 
   744    756   }
   745    757   
   746    758   test_suite "rtree" -description {
   747    759     All R-tree related tests. Provides coverage of source file rtree.c.
   748    760   } -files [glob -nocomplain $::testdir/../ext/rtree/*.test]
          761  +
          762  +test_suite "no_optimization" -description {
          763  +  Run test scripts with optimizations disabled using the
          764  +  sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS) interface.
          765  +} -files {
          766  +  where.test where2.test where3.test where4.test where5.test
          767  +  where6.test where7.test where8.test where9.test
          768  +  whereA.test whereB.test wherelimit.test
          769  +  select1.test select2.test select3.test select4.test select5.test
          770  +  select7.test select8.test selectA.test selectC.test
          771  +} -dbconfig {
          772  +  optimization_control $::dbhandle all 0
          773  +}
   749    774   
   750    775   # End of tests
   751    776   #############################################################################
   752    777   
   753    778   # run_tests NAME OPTIONS
   754    779   #
   755    780   # where available options are:  
................................................................................
   764    789   proc run_tests {name args} {
   765    790     array set options $args
   766    791   
   767    792     set ::G(perm:name)         $name
   768    793     set ::G(perm:prefix)       $options(-prefix)
   769    794     set ::G(perm:presql)       $options(-presql)
   770    795     set ::G(isquick)           1
          796  +  set ::G(perm:dbconfig)     $options(-dbconfig)
   771    797   
   772    798     uplevel $options(-initialize)
   773    799   
   774    800     foreach file [lsort $options(-files)] {
   775    801       if {[file tail $file] == $file} { set file [file join $::testdir $file] }
   776    802       slave_test_file $file
   777    803     }
   778    804   
   779    805     uplevel $options(-shutdown)
   780    806   
   781    807     unset ::G(perm:name)
   782    808     unset ::G(perm:prefix)
   783    809     unset ::G(perm:presql)
          810  +  unset ::G(perm:dbconfig)
   784    811   }
   785    812   
   786    813   proc run_test_suite {name} {
   787    814     if {[info exists ::testspec($name)]==0} {
   788    815       error "No such test suite: $name"
   789    816     }
   790    817     uplevel run_tests $name $::testspec($name)

Changes to test/superlock.test.

    11     11   #
    12     12   
    13     13   set testdir [file dirname $argv0]
    14     14   source $testdir/tester.tcl
    15     15   source $testdir/lock_common.tcl
    16     16   
    17     17   set testprefix superlock
           18  +
           19  +# Test organization:
           20  +#
           21  +#   1.*: Test superlock on a rollback database. Test that once the db is
           22  +#        superlocked, it is not possible for a second client to read from
           23  +#        it.
           24  +#
           25  +#   2.*: Test superlock on a WAL database with zero frames in the WAL file.
           26  +#        Test that once the db is superlocked, it is not possible to read,
           27  +#        write or checkpoint the db.
           28  +#
           29  +#   3.*: As 2.*, for WAL databases with one or more frames in the WAL.
           30  +#
           31  +#   4.*: As 2.*, for WAL databases with one or more checkpointed frames 
           32  +#        in the WAL.
           33  +#
           34  +#   5.*: Test that a call to sqlite3demo_superlock() uses the busy handler
           35  +#        correctly to wait for existing clients to clear on a WAL database.
           36  +#        And returns SQLITE_BUSY if no busy handler is defined or the busy
           37  +#        handler returns 0 before said clients relinquish their locks.
           38  +#
           39  +#   6.*: Test that if a superlocked WAL database is overwritten, existing
           40  +#        clients run the recovery to build the new wal-index after the 
           41  +#        superlock is released.
           42  +#        
           43  +#
    18     44   
    19     45   do_execsql_test 1.1 {
    20     46     CREATE TABLE t1(a, b);
    21     47     INSERT INTO t1 VALUES(1, 2);
    22     48     PRAGMA journal_mode = DELETE;
    23     49   } {delete}
    24     50   
................................................................................
    50     76   do_test 4.2 { sqlite3demo_superlock unlock test.db } {unlock}
    51     77   do_catchsql_test 4.3 { SELECT * FROM t1 }           {1 {database is locked}}
    52     78   do_catchsql_test 4.4 { INSERT INTO t1 VALUES(5, 6)} {1 {database is locked}}
    53     79   do_catchsql_test 4.5 { PRAGMA wal_checkpoint }      {1 {database is locked}}
    54     80   do_test 4.6 { unlock } {}
    55     81   
    56     82   do_multiclient_test tn {
           83  +
    57     84     proc busyhandler {x} {
    58     85       switch -- $x {
    59     86         1 { sql1 "COMMIT" }
    60     87         2 { sql2 "COMMIT" }
    61     88         3 { sql3 "COMMIT" }
    62     89       }
    63     90       lappend ::busylist $x
................................................................................
    88    115     do_test 5.$tn.4 { csql2 { SELECT * FROM t1 } } {1 {database is locked}}
    89    116     do_test 5.$tn.5 { 
    90    117       csql3 { INSERT INTO t1 VALUES(5, 6) } 
    91    118     } {1 {database is locked}}
    92    119     do_test 5.$tn.6 { csql1 "PRAGMA wal_checkpoint" } {1 {database is locked}}
    93    120   
    94    121     do_test 5.$tn.7 { unlock } {}
          122  +
          123  +  
          124  +  do_test 5.$tn.8 {
          125  +    sql1 { BEGIN ; SELECT * FROM t1 }
          126  +    sql2 { BEGIN ; INSERT INTO t1 VALUES(5, 6) }
          127  +    sql3 { BEGIN ; SELECT * FROM t1 }
          128  +  } {1 2 3 4}
          129  +
          130  +  do_test 5.$tn.9 { 
          131  +    list [catch {sqlite3demo_superlock unlock test.db} msg] $msg
          132  +  } {1 {database is locked}}
          133  +  do_test 5.$tn.10 { 
          134  +    sql1 COMMIT
          135  +    list [catch {sqlite3demo_superlock unlock test.db} msg] $msg
          136  +  } {1 {database is locked}}
          137  +  do_test 5.$tn.11 { 
          138  +    sql2 COMMIT
          139  +    list [catch {sqlite3demo_superlock unlock test.db} msg] $msg
          140  +  } {1 {database is locked}}
          141  +  do_test 5.$tn.12 { 
          142  +    sql3 COMMIT
          143  +    list [catch {sqlite3demo_superlock unlock test.db} msg] $msg
          144  +  } {0 unlock}
          145  +  unlock
          146  +}
          147  +
          148  +proc read_content {file} {
          149  +  if {[file exists $file]==0} {return ""}
          150  +  set fd [open $file]
          151  +  fconfigure $fd -encoding binary -translation binary
          152  +  set content [read $fd]
          153  +  close $fd
          154  +  return $content
          155  +}
          156  +
          157  +proc write_content {file content} {
          158  +  set fd [open $file w+]
          159  +  fconfigure $fd -encoding binary -translation binary
          160  +  puts -nonewline $fd $content
          161  +  close $fd
          162  +}
          163  +
          164  +# Both $file1 and $file2 are database files. This function takes a 
          165  +# superlock on each, then exchanges the content of the two files (i.e.
          166  +# overwrites $file1 with the initial contents of $file2, and overwrites
          167  +# $file2 with the initial contents of $file1). The contents of any WAL 
          168  +# file is also exchanged.
          169  +#
          170  +proc db_swap {file1 file2} {
          171  +  sqlite3demo_superlock unlock1 $file1
          172  +  sqlite3demo_superlock unlock2 $file2
          173  +
          174  +  set db1 [read_content $file1]
          175  +  set db2 [read_content $file2]
          176  +  write_content $file1 $db2
          177  +  write_content $file2 $db1
          178  +
          179  +  set wal1 [read_content ${file1}-wal]
          180  +  set wal2 [read_content ${file2}-wal]
          181  +  write_content ${file1}-wal $wal2
          182  +  write_content ${file2}-wal $wal1
          183  +
          184  +  unlock1
          185  +  unlock2
    95    186   }
    96    187   
          188  +forcedelete test.db
          189  +sqlite3 db  test.db
          190  +do_execsql_test 6.1 {
          191  +  ATTACH 'test.db2' AS aux;
          192  +  PRAGMA aux.journal_mode = wal;
          193  +  CREATE TABLE aux.t2(x, y);
          194  +  INSERT INTO aux.t2 VALUES('a', 'b');
          195  +  PRAGMA schema_version = 450;
          196  +  DETACH aux;
          197  +
          198  +  PRAGMA main.journal_mode = wal;
          199  +  CREATE TABLE t1(a, b);
          200  +  INSERT INTO t1 VALUES(1, 2);
          201  +  INSERT INTO t1 VALUES(3, 4);
          202  +  SELECT * FROM t1;
          203  +} {wal wal 1 2 3 4}
          204  +
          205  +
          206  +db_swap test.db2 test.db
          207  +do_catchsql_test 6.2 { SELECT * FROM t1 } {1 {no such table: t1}}
          208  +do_catchsql_test 6.3 { SELECT * FROM t2 } {0 {a b}}
          209  +
          210  +db_swap test.db2 test.db
          211  +do_catchsql_test 6.4 { SELECT * FROM t1 } {0 {1 2 3 4}}
          212  +do_catchsql_test 6.5 { SELECT * FROM t2 } {1 {no such table: t2}}
          213  +
          214  +do_execsql_test  6.6 { PRAGMA wal_checkpoint }
          215  +
          216  +db_swap test.db2 test.db
          217  +do_catchsql_test 6.7 { SELECT * FROM t1 } {1 {no such table: t1}}
          218  +do_catchsql_test 6.8 { SELECT * FROM t2 } {0 {a b}}
          219  +
          220  +db_swap test.db2 test.db
          221  +do_catchsql_test 6.9 { SELECT * FROM t1 } {0 {1 2 3 4}}
          222  +do_catchsql_test 6.10 { SELECT * FROM t2 } {1 {no such table: t2}}
          223  +
          224  +do_execsql_test  6.11 { 
          225  +  PRAGMA journal_mode = delete;
          226  +  PRAGMA page_size = 512;
          227  +  VACUUM;
          228  +  PRAGMA journal_mode = wal;
          229  +  INSERT INTO t1 VALUES(5, 6);
          230  +} {delete wal}
          231  +
          232  +db_swap test.db2 test.db
          233  +do_catchsql_test 6.12 { SELECT * FROM t1 } {1 {no such table: t1}}
          234  +do_catchsql_test 6.13 { SELECT * FROM t2 } {0 {a b}}
          235  +
          236  +db_swap test.db2 test.db
          237  +do_catchsql_test 6.14 { SELECT * FROM t1 } {0 {1 2 3 4 5 6}}
          238  +do_catchsql_test 6.15 { SELECT * FROM t2 } {1 {no such table: t2}}
    97    239   
    98    240   finish_test

Changes to test/tester.tcl.

   105    105           lappend args -key {xyzzy}
   106    106         }
   107    107   
   108    108         set res [uplevel 1 sqlite_orig $args]
   109    109         if {[info exists ::G(perm:presql)]} {
   110    110           [lindex $args 0] eval $::G(perm:presql)
   111    111         }
          112  +      if {[info exists ::G(perm:dbconfig)]} {
          113  +        set ::dbhandle [lindex $args 0]
          114  +        uplevel #0 $::G(perm:dbconfig)
          115  +      }
   112    116         set res
   113    117       } else {
   114    118         # This command is not opening a new database connection. Pass the 
   115    119         # arguments through to the C implemenation as the are.
   116    120         #
   117    121         uplevel 1 sqlite_orig $args
   118    122       }
................................................................................
   333    337       puts "\nExpected: \[$expected\]\n     Got: \[$result\]"
   334    338       fail_test $name
   335    339     } else {
   336    340       puts " Ok"
   337    341     }
   338    342     flush stdout
   339    343   }
   340         -    
          344  +
   341    345   proc fix_testname {varname} {
   342    346     upvar $varname testname
   343    347     if {[info exists ::testprefix] 
   344    348      && [string is digit [string range $testname 0 0]]
   345    349     } {
   346    350       set testname "${::testprefix}-$testname"
   347    351     }
................................................................................
  1403   1407     catch { db36231 func a_string a_string }
  1404   1408     execsql $sql db36231
  1405   1409     db36231 close
  1406   1410     hexio_write test.db 28 $A
  1407   1411     hexio_write test.db 92 $B
  1408   1412     return ""
  1409   1413   }
         1414  +
         1415  +proc db_save {} {
         1416  +  foreach f [glob -nocomplain sv_test.db*] { forcedelete $f }
         1417  +  foreach f [glob -nocomplain test.db*] {
         1418  +    set f2 "sv_$f"
         1419  +    file copy -force $f $f2
         1420  +  }
         1421  +}
         1422  +proc db_save_and_close {} {
         1423  +  db_save
         1424  +  catch { db close }
         1425  +  return ""
         1426  +}
         1427  +proc db_restore {} {
         1428  +  foreach f [glob -nocomplain test.db*] { forcedelete $f }
         1429  +  foreach f2 [glob -nocomplain sv_test.db*] {
         1430  +    set f [string range $f2 3 end]
         1431  +    file copy -force $f2 $f
         1432  +  }
         1433  +}
         1434  +proc db_restore_and_reopen {{dbfile test.db}} {
         1435  +  catch { db close }
         1436  +  db_restore
         1437  +  sqlite3 db $dbfile
         1438  +}
         1439  +proc db_delete_and_reopen {{file test.db}} {
         1440  +  catch { db close }
         1441  +  foreach f [glob -nocomplain test.db*] { file delete -force $f }
         1442  +  sqlite3 db $file
         1443  +}
  1410   1444   
  1411   1445   # If the library is compiled with the SQLITE_DEFAULT_AUTOVACUUM macro set
  1412   1446   # to non-zero, then set the global variable $AUTOVACUUM to 1.
  1413   1447   set AUTOVACUUM $sqlite_options(default_autovacuum)
  1414   1448   
  1415   1449   source $testdir/thread_common.tcl
  1416   1450   source $testdir/malloc_common.tcl

Added test/tkt-80ba201079.test.

            1  +# 2010 December 6
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# This file implements regression tests for SQLite library. Specifically,
           12  +# it tests that ticket [80ba201079ea608071d22a57856b940ea3ac53ce] is
           13  +# resolved.  That ticket is about an incorrect result that appears when
           14  +# an index is added.  The root cause is that a constant is being used
           15  +# without initialization when the OR optimization applies in the WHERE clause.
           16  +#
           17  +
           18  +set testdir [file dirname $argv0]
           19  +source $testdir/tester.tcl
           20  +set ::testprefix tkt-80ba2
           21  +
           22  +do_test tkt-80ba2-100 {
           23  +  db eval {
           24  +    CREATE TABLE t1(a);
           25  +    INSERT INTO t1 VALUES('A');
           26  +    CREATE TABLE t2(b);
           27  +    INSERT INTO t2 VALUES('B');
           28  +    CREATE TABLE t3(c);
           29  +    INSERT INTO t3 VALUES('C');
           30  +    SELECT * FROM t1, t2
           31  +     WHERE (a='A' AND b='X')
           32  +        OR (a='A' AND EXISTS (SELECT * FROM t3 WHERE c='C'));
           33  +  }
           34  +} {A B}
           35  +do_test tkt-80ba2-101 {
           36  +  db eval {
           37  +    CREATE INDEX i1 ON t1(a);
           38  +    SELECT * FROM t1, t2
           39  +     WHERE (a='A' AND b='X')
           40  +        OR (a='A' AND EXISTS (SELECT * FROM t3 WHERE c='C'));
           41  +  }
           42  +} {A B}
           43  +do_test tkt-80ba2-102 {
           44  +  optimization_control db factor-constants 0
           45  +  db cache flush
           46  +  db eval {
           47  +    SELECT * FROM t1, t2
           48  +     WHERE (a='A' AND b='X')
           49  +        OR (a='A' AND EXISTS (SELECT * FROM t3 WHERE c='C'));
           50  +  }
           51  +} {A B}
           52  +optimization_control db all 1
           53  +
           54  +# Verify that the optimization_control command is actually working
           55  +#
           56  +do_test tkt-80ba2-150 {
           57  +  optimization_control db factor-constants 1
           58  +  db cache flush
           59  +  set x1 [db eval {EXPLAIN 
           60  +    SELECT * FROM t1, t2
           61  +     WHERE (a='A' AND b='X')
           62  +        OR (a='A' AND EXISTS (SELECT * FROM t3 WHERE c='C'));}]
           63  +  optimization_control db factor-constants 0
           64  +  db cache flush
           65  +  set x2 [db eval {EXPLAIN 
           66  +    SELECT * FROM t1, t2
           67  +     WHERE (a='A' AND b='X')
           68  +        OR (a='A' AND EXISTS (SELECT * FROM t3 WHERE c='C'));}]
           69  +
           70  +  expr {$x1==$x2}
           71  +} {0}
           72  +
           73  +do_test tkt-80ba2-200 {
           74  +  db eval {
           75  +    CREATE TABLE entry_types (
           76  +                        id     integer primary key,
           77  +                        name   text
           78  +                    );
           79  +    INSERT INTO "entry_types" VALUES(100,'cli_command');
           80  +    INSERT INTO "entry_types" VALUES(300,'object_change');
           81  +    CREATE TABLE object_changes (
           82  +                        change_id    integer primary key,
           83  +                        system_id    int,
           84  +                        obj_id       int,
           85  +                        obj_context  text,
           86  +                        change_type  int,
           87  +                        command_id   int
           88  +                    );
           89  +    INSERT INTO "object_changes" VALUES(1551,1,114608,'exported_pools',1,2114);
           90  +    INSERT INTO "object_changes" VALUES(2048,1,114608,'exported_pools',2,2319);
           91  +    CREATE TABLE timeline (
           92  +                        rowid        integer primary key,
           93  +                        timestamp    text,
           94  +                        system_id    int,
           95  +                        entry_type   int,
           96  +                        entry_id     int
           97  +                    );
           98  +    INSERT INTO "timeline" VALUES(6735,'2010-11-21 17:08:27.000',1,300,2048);
           99  +    INSERT INTO "timeline" VALUES(6825,'2010-11-21 17:09:21.000',1,300,2114);
          100  +    SELECT entry_type,
          101  +           entry_types.name,
          102  +           entry_id
          103  +      FROM timeline JOIN entry_types ON entry_type = entry_types.id
          104  +     WHERE (entry_types.name = 'cli_command' AND entry_id=2114)
          105  +        OR (entry_types.name = 'object_change'
          106  +             AND entry_id IN (SELECT change_id
          107  +                              FROM object_changes
          108  +                               WHERE obj_context = 'exported_pools'));
          109  +  }
          110  +} {300 object_change 2048}
          111  +do_test tkt-80ba2-201 {
          112  +  db eval {
          113  +    CREATE INDEX timeline_entry_id_idx on timeline(entry_id);
          114  +    SELECT entry_type,
          115  +           entry_types.name,
          116  +           entry_id
          117  +      FROM timeline JOIN entry_types ON entry_type = entry_types.id
          118  +     WHERE (entry_types.name = 'cli_command' AND entry_id=2114)
          119  +        OR (entry_types.name = 'object_change'
          120  +             AND entry_id IN (SELECT change_id
          121  +                              FROM object_changes
          122  +                               WHERE obj_context = 'exported_pools'));
          123  +  }
          124  +} {300 object_change 2048}
          125  +do_test tkt-80ba2-202 {
          126  +  optimization_control db factor-constants 0
          127  +  db cache flush
          128  +  db eval {
          129  +    SELECT entry_type,
          130  +           entry_types.name,
          131  +           entry_id
          132  +      FROM timeline JOIN entry_types ON entry_type = entry_types.id
          133  +     WHERE (entry_types.name = 'cli_command' AND entry_id=2114)
          134  +        OR (entry_types.name = 'object_change'
          135  +             AND entry_id IN (SELECT change_id
          136  +                              FROM object_changes
          137  +                               WHERE obj_context = 'exported_pools'));
          138  +  }
          139  +} {300 object_change 2048}
          140  +
          141  +#-------------------------------------------------------------------------
          142  +#
          143  +
          144  +drop_all_tables
          145  +do_execsql_test 301 {
          146  +  CREATE TABLE t1(a, b, c);
          147  +  CREATE INDEX i1 ON t1(a);
          148  +  CREATE INDEX i2 ON t1(b);
          149  +  CREATE TABLE t2(d, e);
          150  +
          151  +  INSERT INTO t1 VALUES('A', 'B', 'C');
          152  +  INSERT INTO t2 VALUES('D', 'E');
          153  +}
          154  +
          155  +do_execsql_test 302 {
          156  +  SELECT * FROM t1, t2 WHERE
          157  +    (a='A' AND d='E') OR
          158  +    (b='B' AND c IN ('C', 'D', 'E'))
          159  +} {A B C D E}
          160  +
          161  +do_execsql_test 303 {
          162  +  SELECT * FROM t1, t2 WHERE
          163  +    (a='A' AND d='E') OR
          164  +    (b='B' AND c IN (SELECT c FROM t1))
          165  +} {A B C D E}
          166  +
          167  +do_execsql_test 304 {
          168  +  SELECT * FROM t1, t2 WHERE
          169  +    (a='A' AND d='E') OR
          170  +    (b='B' AND c IN (SELECT 'B' UNION SELECT 'C' UNION SELECT 'D'))
          171  +} {A B C D E}
          172  +
          173  +do_execsql_test 305 {
          174  +  SELECT * FROM t1, t2 WHERE
          175  +    (b='B' AND c IN ('C', 'D', 'E')) OR
          176  +    (a='A' AND d='E')
          177  +} {A B C D E}
          178  +
          179  +do_execsql_test 306 {
          180  +  SELECT * FROM t1, t2 WHERE
          181  +    (b='B' AND c IN (SELECT c FROM t1)) OR
          182  +    (a='A' AND d='E')
          183  +} {A B C D E}
          184  +
          185  +do_execsql_test 307 {
          186  +  SELECT * FROM t1, t2 WHERE
          187  +    (b='B' AND c IN (SELECT 'B' UNION SELECT 'C' UNION SELECT 'D')) OR
          188  +    (a='A' AND d='E')
          189  +} {A B C D E}
          190  +
          191  +finish_test

Changes to test/triggerC.test.

   933    933   do_test triggerC-12.2 {
   934    934     db eval { SELECT * FROM t1 } {
   935    935       if {$a == 3} { execsql { DROP TRIGGER tr1 } }
   936    936     }
   937    937     execsql { SELECT count(*) FROM sqlite_master }
   938    938   } {1}
   939    939   
          940  +do_execsql_test triggerC-13.1 {
          941  +  PRAGMA recursive_triggers = ON;
          942  +  CREATE TABLE t12(a, b);
          943  +  INSERT INTO t12 VALUES(1, 2);
          944  +  CREATE TRIGGER tr12 AFTER UPDATE ON t12 BEGIN
          945  +    UPDATE t12 SET a=new.a+1, b=new.b+1;
          946  +  END;
          947  +} {}
          948  +do_catchsql_test triggerC-13.2 {
          949  +  UPDATE t12 SET a=a+1, b=b+1;
          950  +} {1 {too many levels of trigger recursion}}
          951  +
   940    952   
   941    953   
   942    954   finish_test

Changes to test/wal2.test.

    14     14   #
    15     15   
    16     16   set testdir [file dirname $argv0]
    17     17   source $testdir/tester.tcl
    18     18   source $testdir/lock_common.tcl
    19     19   source $testdir/malloc_common.tcl
    20     20   source $testdir/wal_common.tcl
           21  +
           22  +set testprefix wal2
    21     23   
    22     24   ifcapable !wal {finish_test ; return }
    23     25   if { ![wal_is_ok] || [path_is_dos "."]} {
    24     26     finish_test 
    25     27     return 
    26     28   }
    27     29   
................................................................................
  1152   1154         set b(1,1) {0 {}}
  1153   1155         do_test wal2-13.$tn.4 {
  1154   1156           catchsql { INSERT INTO t1 DEFAULT VALUES }
  1155   1157         } $b($can_read,$can_write)
  1156   1158       }
  1157   1159       catch { db close }
  1158   1160     }
  1159         -}
         1161  +} 
  1160   1162   
  1161   1163   #-------------------------------------------------------------------------
  1162   1164   # Test that "PRAGMA checkpoint_fullsync" appears to be working.
  1163   1165   #
  1164   1166   foreach {tn sql reslist} {
  1165   1167     1 { }                                 {8 0 3 0 5 0}
  1166   1168     2 { PRAGMA checkpoint_fullfsync = 1 } {8 4 3 2 5 2}
................................................................................
  1206   1208       execsql { INSERT INTO t1 VALUES(9, 10) }
  1207   1209       execsql { INSERT INTO t1 VALUES(11, 12) }
  1208   1210       execsql { INSERT INTO t1 VALUES(13, 14) }
  1209   1211       db close
  1210   1212       list $sqlite_sync_count $sqlite_fullsync_count
  1211   1213     } [lrange $reslist 4 5]
  1212   1214   }
         1215  +
         1216  +catch { db close }
         1217  +
         1218  +# PRAGMA checkpoint_fullsync
         1219  +# PRAGMA fullfsync
         1220  +# PRAGMA synchronous
         1221  +#
         1222  +foreach {tn settings commit_sync ckpt_sync} {
         1223  +  1  {0 0 off}     {0 0}  {0 0}
         1224  +  2  {0 0 normal}  {0 0}  {2 0}
         1225  +  3  {0 0 full}    {1 0}  {2 0}
         1226  +
         1227  +  4  {0 1 off}     {0 0}  {0 0}
         1228  +  5  {0 1 normal}  {0 0}  {0 2}
         1229  +  6  {0 1 full}    {0 1}  {0 2}
         1230  +
         1231  +  7  {1 0 off}     {0 0}  {0 0}
         1232  +  8  {1 0 normal}  {0 0}  {0 2}
         1233  +  9  {1 0 full}    {1 0}  {0 2}
         1234  +
         1235  +  10 {1 1 off}     {0 0}  {0 0}
         1236  +  11 {1 1 normal}  {0 0}  {0 2}
         1237  +  12 {1 1 full}    {0 1}  {0 2}
         1238  +} {
         1239  +  forcedelete test.db
         1240  +
         1241  +  testvfs tvfs -default 1
         1242  +  tvfs filter xSync
         1243  +  tvfs script xSyncCb
         1244  +  proc xSyncCb {method file fileid flags} {
         1245  +    incr ::sync($flags)
         1246  +  }
         1247  +
         1248  +  sqlite3 db test.db
         1249  +  do_execsql_test 15.$tn.1 "
         1250  +    CREATE TABLE t1(x);
         1251  +    PRAGMA journal_mode = WAL;
         1252  +    PRAGMA checkpoint_fullfsync = [lindex $settings 0];
         1253  +    PRAGMA fullfsync = [lindex $settings 1];
         1254  +    PRAGMA synchronous = [lindex $settings 2];
         1255  +  " {wal}
         1256  +
         1257  +  do_test 15.$tn.2 {
         1258  +    set sync(normal) 0
         1259  +    set sync(full) 0
         1260  +    execsql { INSERT INTO t1 VALUES('abc') }
         1261  +    list $::sync(normal) $::sync(full)
         1262  +  } $commit_sync
         1263  +
         1264  +  do_test 15.$tn.3 {
         1265  +    set sync(normal) 0
         1266  +    set sync(full) 0
         1267  +    execsql { INSERT INTO t1 VALUES('def') }
         1268  +    list $::sync(normal) $::sync(full)
         1269  +  } $commit_sync
         1270  +
         1271  +  do_test 15.$tn.4 {
         1272  +    set sync(normal) 0
         1273  +    set sync(full) 0
         1274  +    execsql { PRAGMA wal_checkpoint }
         1275  +    list $::sync(normal) $::sync(full)
         1276  +  } $ckpt_sync
         1277  +  
         1278  +  db close
         1279  +  tvfs delete
         1280  +}
  1213   1281   
  1214   1282   
  1215   1283   
  1216   1284   finish_test

Changes to test/wal3.test.

   703    703   # transaction.
   704    704   #
   705    705   # This test case verifies that if an exclusive lock cannot be obtained
   706    706   # on any aReadMark[] slot (because there are already several readers),
   707    707   # the client takes a shared-lock on a slot without modifying the value
   708    708   # and continues.
   709    709   #
          710  +set nConn 50
          711  +if { [string match *BSD $tcl_platform(os)] } { set nConn 35 }
   710    712   do_test wal3-9.0 {
   711    713     file delete -force test.db test.db-journal test.db wal
   712    714     sqlite3 db test.db
   713    715     execsql {
   714    716       PRAGMA page_size = 1024;
   715    717       PRAGMA journal_mode = WAL;
   716    718       CREATE TABLE whoami(x);
   717    719       INSERT INTO whoami VALUES('nobody');
   718    720     }
   719    721   } {wal}
   720         -for {set i 0} {$i < 50} {incr i} {
          722  +for {set i 0} {$i < $nConn} {incr i} {
   721    723     set c db$i
   722    724     do_test wal3-9.1.$i {
   723    725       sqlite3 $c test.db
   724    726       execsql { UPDATE whoami SET x = $c }
   725    727       execsql {
   726    728         BEGIN;
   727    729         SELECT * FROM whoami
   728    730       } $c
   729    731     } $c
   730    732   }
   731         -for {set i 0} {$i < 50} {incr i} {
          733  +for {set i 0} {$i < $nConn} {incr i} {
   732    734     set c db$i
   733    735     do_test wal3-9.2.$i {
   734    736       execsql { SELECT * FROM whoami } $c
   735    737     } $c
   736    738   }
   737    739   
   738    740   set sz [expr 1024 * (2+$AUTOVACUUM)]
   739    741   do_test wal3-9.3 {
   740         -  for {set i 0} {$i < 49} {incr i} { db$i close }
          742  +  for {set i 0} {$i < ($nConn-1)} {incr i} { db$i close }
   741    743     execsql { PRAGMA wal_checkpoint } 
   742    744     byte_is_zero test.db [expr $sz-1024]
   743    745   } {1}
   744    746   do_test wal3-9.4 {
   745         -  db49 close
          747  +  db[expr $nConn-1] close
   746    748     execsql { PRAGMA wal_checkpoint } 
   747    749     set sz2 [file size test.db]
   748    750     byte_is_zero test.db [expr $sz-1024]
   749    751   } {0}
   750    752   
   751    753   do_multiclient_test tn {
   752    754     do_test wal3-10.$tn.1 {

Added test/wal6.test.

            1  +# 2010 December 1
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# This file implements regression tests for SQLite library.  The
           12  +# focus of this file is testing the operation of the library in
           13  +# "PRAGMA journal_mode=WAL" mode.
           14  +#
           15  +
           16  +set testdir [file dirname $argv0]
           17  +source $testdir/tester.tcl
           18  +source $testdir/lock_common.tcl
           19  +source $testdir/wal_common.tcl
           20  +source $testdir/malloc_common.tcl
           21  +ifcapable !wal {finish_test ; return }
           22  +
           23  +#-------------------------------------------------------------------------
           24  +# Changing to WAL mode in one connection forces the change in others.
           25  +#
           26  +db close
           27  +forcedelete test.db
           28  +
           29  +set all_journal_modes {delete persist truncate memory off}
           30  +foreach jmode $all_journal_modes {
           31  +
           32  +	do_test wal6-1.0.$jmode {
           33  +    sqlite3 db test.db
           34  +    execsql "PRAGMA journal_mode = $jmode;"
           35  +	} $jmode
           36  +
           37  +	do_test wal6-1.1.$jmode {
           38  +	  execsql {
           39  +	    CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
           40  +	    INSERT INTO t1 VALUES(1,2);
           41  +	    SELECT * FROM t1;
           42  +	  }
           43  +	} {1 2}
           44  +
           45  +# Under Windows, you'll get an error trying to delete
           46  +# a file this is already opened.  For now, make sure 
           47  +# we get that error, then close the first connection
           48  +# so the other tests work.
           49  +if {$tcl_platform(platform)=="windows"} {
           50  +  if {$jmode=="persist" || $jmode=="truncate"} {
           51  +	  do_test wal6-1.2.$jmode.win {
           52  +	    sqlite3 db2 test.db
           53  +	    catchsql {
           54  +		    PRAGMA journal_mode=WAL;
           55  +	    } db2
           56  +	  } {1 {disk I/O error}}
           57  +  	db2 close
           58  +	  db close
           59  +  }
           60  +}
           61  +
           62  +	do_test wal6-1.2.$jmode {
           63  +	  sqlite3 db2 test.db
           64  +	  execsql {
           65  +		PRAGMA journal_mode=WAL;
           66  +		INSERT INTO t1 VALUES(3,4);
           67  +		SELECT * FROM t1 ORDER BY a;
           68  +	  } db2
           69  +	} {wal 1 2 3 4}
           70  +
           71  +if {$tcl_platform(platform)=="windows"} {
           72  +  if {$jmode=="persist" || $jmode=="truncate"} {
           73  +	  sqlite3 db test.db
           74  +  }
           75  +}
           76  +
           77  +	do_test wal6-1.3.$jmode {
           78  +	  execsql {
           79  +		  SELECT * FROM t1 ORDER BY a;
           80  +	  }
           81  +	} {1 2 3 4}
           82  +
           83  +	db close
           84  +	db2 close
           85  +  forcedelete test.db
           86  +
           87  +}
           88  +
           89  +finish_test
           90  +

Changes to tool/lemon.c.

    16     16   #ifndef __WIN32__
    17     17   #   if defined(_WIN32) || defined(WIN32)
    18     18   #	define __WIN32__
    19     19   #   endif
    20     20   #endif
    21     21   
    22     22   #ifdef __WIN32__
    23         -extern int access();
           23  +#ifdef __cplusplus
           24  +extern "C" {
           25  +#endif
           26  +extern int access(const char *path, int mode);
           27  +#ifdef __cplusplus
           28  +}
           29  +#endif
    24     30   #else
    25     31   #include <unistd.h>
    26     32   #endif
    27     33   
    28     34   /* #define PRIVATE static */
    29     35   #define PRIVATE
    30     36   
................................................................................
  3259   3265     if( n<=0 ){
  3260   3266       if( n<0 ){
  3261   3267         used += n;
  3262   3268         assert( used>=0 );
  3263   3269       }
  3264   3270       n = lemonStrlen(zText);
  3265   3271     }
  3266         -  if( n+sizeof(zInt)*2+used >= alloced ){
         3272  +  if( (int) (n+sizeof(zInt)*2+used) >= alloced ){
  3267   3273       alloced = n + sizeof(zInt)*2 + used + 200;
  3268   3274       z = (char *) realloc(z,  alloced);
  3269   3275     }
  3270   3276     if( z==0 ) return empty;
  3271   3277     while( n-- > 0 ){
  3272   3278       c = *(zText++);
  3273   3279       if( c=='%' && n>0 && zText[0]=='d' ){