/ Check-in [9682c043]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Merge enhancements from trunk.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | tempfiles-lazy-open
Files: files | file ages | folders
SHA1: 9682c0433c04713c28bd9105a7e20af7372f873e
User & Date: drh 2016-04-12 16:10:10
Context
2016-04-12
19:09
Once a temporary database file has been opened, flush all dirty pages to disk when comitting a transaction. check-in: bbac71aa user: dan tags: tempfiles-lazy-open
16:10
Merge enhancements from trunk. check-in: 9682c043 user: drh tags: tempfiles-lazy-open
16:04
Add the sqlite3_snapshot_cmp() interface (available only with SQLITE_ENABLE_SNAPSHOT). check-in: 7e728965 user: drh tags: trunk
2016-04-11
19:24
Fix a typo in temptable2.test. check-in: 04b1890f user: dan tags: tempfiles-lazy-open
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to Makefile.msc.

  1878   1878   
  1879   1879   fts3_write.lo:	$(TOP)\ext\fts3\fts3_write.c $(HDR) $(EXTHDR)
  1880   1880   	$(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_write.c
  1881   1881   
  1882   1882   rtree.lo:	$(TOP)\ext\rtree\rtree.c $(HDR) $(EXTHDR)
  1883   1883   	$(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\rtree\rtree.c
  1884   1884   
  1885         -sqlite3session.lo:	$(TOP)\ext\session\sqlite3sesion.c $(HDR) $(EXTHDR)
         1885  +sqlite3session.lo:	$(TOP)\ext\session\sqlite3session.c $(HDR) $(EXTHDR)
  1886   1886   	$(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\session\sqlite3session.c
  1887   1887   
  1888   1888   # FTS5 things
  1889   1889   #
  1890   1890   FTS5_SRC = \
  1891   1891      $(TOP)\ext\fts5\fts5.h \
  1892   1892      $(TOP)\ext\fts5\fts5Int.h \

Changes to src/expr.c.

   467    467       pNew->op = (u8)op;
   468    468       pNew->iAgg = -1;
   469    469       if( pToken ){
   470    470         if( nExtra==0 ){
   471    471           pNew->flags |= EP_IntValue;
   472    472           pNew->u.iValue = iValue;
   473    473         }else{
   474         -        int c;
   475    474           pNew->u.zToken = (char*)&pNew[1];
   476    475           assert( pToken->z!=0 || pToken->n==0 );
   477    476           if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n);
   478    477           pNew->u.zToken[pToken->n] = 0;
   479         -        if( dequote && nExtra>=3 
   480         -             && ((c = pToken->z[0])=='\'' || c=='"' || c=='[' || c=='`') ){
          478  +        if( dequote && sqlite3Isquote(pNew->u.zToken[0]) ){
          479  +          if( pNew->u.zToken[0]=='"' ) pNew->flags |= EP_DblQuoted;
   481    480             sqlite3Dequote(pNew->u.zToken);
   482         -          if( c=='"' ) pNew->flags |= EP_DblQuoted;
   483    481           }
   484    482         }
   485    483       }
   486    484   #if SQLITE_MAX_EXPR_DEPTH>0
   487    485       pNew->nHeight = 1;
   488    486   #endif  
   489    487     }
................................................................................
  1225   1223     assert( pList!=0 || pParse->db->mallocFailed!=0 );
  1226   1224     if( pList ){
  1227   1225       struct ExprList_item *pItem;
  1228   1226       assert( pList->nExpr>0 );
  1229   1227       pItem = &pList->a[pList->nExpr-1];
  1230   1228       assert( pItem->zName==0 );
  1231   1229       pItem->zName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n);
  1232         -    if( dequote && pItem->zName ) sqlite3Dequote(pItem->zName);
         1230  +    if( dequote ) sqlite3Dequote(pItem->zName);
  1233   1231     }
  1234   1232   }
  1235   1233   
  1236   1234   /*
  1237   1235   ** Set the ExprList.a[].zSpan element of the most recently added item
  1238   1236   ** on the expression list.
  1239   1237   **

Changes to src/global.c.

    66     66   **   isspace()                        0x01
    67     67   **   isalpha()                        0x02
    68     68   **   isdigit()                        0x04
    69     69   **   isalnum()                        0x06
    70     70   **   isxdigit()                       0x08
    71     71   **   toupper()                        0x20
    72     72   **   SQLite identifier character      0x40
           73  +**   Quote character                  0x80
    73     74   **
    74     75   ** Bit 0x20 is set if the mapped character requires translation to upper
    75     76   ** case. i.e. if the character is a lower-case ASCII character.
    76     77   ** If x is a lower-case ASCII character, then its upper-case equivalent
    77     78   ** is (x - 0x20). Therefore toupper() can be implemented as:
    78     79   **
    79     80   **   (x & ~(map[x]&0x20))
................................................................................
    91     92   */
    92     93   #ifdef SQLITE_ASCII
    93     94   const unsigned char sqlite3CtypeMap[256] = {
    94     95     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 00..07    ........ */
    95     96     0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,  /* 08..0f    ........ */
    96     97     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 10..17    ........ */
    97     98     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 18..1f    ........ */
    98         -  0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,  /* 20..27     !"#$%&' */
           99  +  0x01, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x80,  /* 20..27     !"#$%&' */
    99    100     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 28..2f    ()*+,-./ */
   100    101     0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,  /* 30..37    01234567 */
   101    102     0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 38..3f    89:;<=>? */
   102    103   
   103    104     0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x02,  /* 40..47    @ABCDEFG */
   104    105     0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,  /* 48..4f    HIJKLMNO */
   105    106     0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,  /* 50..57    PQRSTUVW */
   106         -  0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x40,  /* 58..5f    XYZ[\]^_ */
   107         -  0x00, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22,  /* 60..67    `abcdefg */
          107  +  0x02, 0x02, 0x02, 0x80, 0x00, 0x00, 0x00, 0x40,  /* 58..5f    XYZ[\]^_ */
          108  +  0x80, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22,  /* 60..67    `abcdefg */
   108    109     0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,  /* 68..6f    hijklmno */
   109    110     0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,  /* 70..77    pqrstuvw */
   110    111     0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 78..7f    xyz{|}~. */
   111    112   
   112    113     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* 80..87    ........ */
   113    114     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* 88..8f    ........ */
   114    115     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* 90..97    ........ */

Changes to src/memjournal.c.

     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   **
    13     13   ** This file contains code use to implement an in-memory rollback journal.
    14     14   ** The in-memory rollback journal is used to journal transactions for
    15     15   ** ":memory:" databases and when the journal_mode=MEMORY pragma is used.
           16  +**
           17  +** Update:  The in-memory journal is also used to temporarily cache
           18  +** smaller journals that are not critical for power-loss recovery.
           19  +** For example, statement journals that are not too big will be held
           20  +** entirely in memory, thus reducing the number of file I/O calls, and
           21  +** more importantly, reducing temporary file creation events.  If these
           22  +** journals become too large for memory, they are spilled to disk.  But
           23  +** in the common case, they are usually small and no file I/O needs to
           24  +** occur.
    16     25   */
    17     26   #include "sqliteInt.h"
    18     27   
    19     28   /* Forward references to internal structures */
    20     29   typedef struct MemJournal MemJournal;
    21     30   typedef struct FilePoint FilePoint;
    22     31   typedef struct FileChunk FileChunk;

Changes to src/select.c.

    70     70       sqlite3SrcListDelete(db, p->pSrc);
    71     71       sqlite3ExprDelete(db, p->pWhere);
    72     72       sqlite3ExprListDelete(db, p->pGroupBy);
    73     73       sqlite3ExprDelete(db, p->pHaving);
    74     74       sqlite3ExprListDelete(db, p->pOrderBy);
    75     75       sqlite3ExprDelete(db, p->pLimit);
    76     76       sqlite3ExprDelete(db, p->pOffset);
    77         -    sqlite3WithDelete(db, p->pWith);
           77  +    if( p->pWith ) sqlite3WithDelete(db, p->pWith);
    78     78       if( bFree ) sqlite3DbFree(db, p);
    79     79       p = pPrior;
    80     80       bFree = 1;
    81     81     }
    82     82   }
    83     83   
    84     84   /*
................................................................................
   165    165   #endif
   166    166   
   167    167   
   168    168   /*
   169    169   ** Delete the given Select structure and all of its substructures.
   170    170   */
   171    171   void sqlite3SelectDelete(sqlite3 *db, Select *p){
   172         -  clearSelect(db, p, 1);
          172  +  if( p ) clearSelect(db, p, 1);
   173    173   }
   174    174   
   175    175   /*
   176    176   ** Return a pointer to the right-most SELECT statement in a compound.
   177    177   */
   178    178   static Select *findRightmost(Select *p){
   179    179     while( p->pNext ) p = p->pNext;
................................................................................
  1785   1785     return pTab;
  1786   1786   }
  1787   1787   
  1788   1788   /*
  1789   1789   ** Get a VDBE for the given parser context.  Create a new one if necessary.
  1790   1790   ** If an error occurs, return NULL and leave a message in pParse.
  1791   1791   */
  1792         -Vdbe *sqlite3GetVdbe(Parse *pParse){
  1793         -  Vdbe *v = pParse->pVdbe;
  1794         -  if( v==0 ){
  1795         -    v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
  1796         -    if( v ) sqlite3VdbeAddOp0(v, OP_Init);
  1797         -    if( pParse->pToplevel==0
  1798         -     && OptimizationEnabled(pParse->db,SQLITE_FactorOutConst)
  1799         -    ){
  1800         -      pParse->okConstFactor = 1;
  1801         -    }
  1802         -
         1792  +static SQLITE_NOINLINE Vdbe *allocVdbe(Parse *pParse){
         1793  +  Vdbe *v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
         1794  +  if( v ) sqlite3VdbeAddOp0(v, OP_Init);
         1795  +  if( pParse->pToplevel==0
         1796  +   && OptimizationEnabled(pParse->db,SQLITE_FactorOutConst)
         1797  +  ){
         1798  +    pParse->okConstFactor = 1;
  1803   1799     }
  1804   1800     return v;
         1801  +}
         1802  +Vdbe *sqlite3GetVdbe(Parse *pParse){
         1803  +  Vdbe *v = pParse->pVdbe;
         1804  +  return v ? v : allocVdbe(pParse);
  1805   1805   }
  1806   1806   
  1807   1807   
  1808   1808   /*
  1809   1809   ** Compute the iLimit and iOffset fields of the SELECT based on the
  1810   1810   ** pLimit and pOffset expressions.  pLimit and pOffset hold the expressions
  1811   1811   ** that appear in the original SQL statement after the LIMIT and OFFSET

Changes to src/sqlite.h.in.

  8123   8123   ** The application must eventually free every [sqlite3_snapshot] object
  8124   8124   ** using this routine to avoid a memory leak.
  8125   8125   **
  8126   8126   ** The [sqlite3_snapshot_free()] interface is only available when the
  8127   8127   ** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
  8128   8128   */
  8129   8129   SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*);
         8130  +
         8131  +/*
         8132  +** CAPI3REF: Compare the ages of two snapshot handles.
         8133  +** EXPERIMENTAL
         8134  +**
         8135  +** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages
         8136  +** of two valid snapshot handles. 
         8137  +**
         8138  +** If the two snapshot handles are not associated with the same database 
         8139  +** file, the result of the comparison is undefined. 
         8140  +**
         8141  +** Additionally, the result of the comparison is only valid if both of the
         8142  +** snapshot handles were obtained by calling sqlite3_snapshot_get() since the
         8143  +** last time the wal file was deleted. The wal file is deleted when the
         8144  +** database is changed back to rollback mode or when the number of database
         8145  +** clients drops to zero. If either snapshot handle was obtained before the 
         8146  +** wal file was last deleted, the value returned by this function 
         8147  +** is undefined.
         8148  +**
         8149  +** Otherwise, this API returns a negative value if P1 refers to an older
         8150  +** snapshot than P2, zero if the two handles refer to the same database
         8151  +** snapshot, and a positive value if P1 is a newer snapshot than P2.
         8152  +*/
         8153  +SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
         8154  +  sqlite3_snapshot *p1,
         8155  +  sqlite3_snapshot *p2
         8156  +);
  8130   8157   
  8131   8158   /*
  8132   8159   ** Undo the hack that converts floating point types to integer for
  8133   8160   ** builds on processors without floating point support.
  8134   8161   */
  8135   8162   #ifdef SQLITE_OMIT_FLOATING_POINT
  8136   8163   # undef double
  8137   8164   #endif
  8138   8165   
  8139   8166   #ifdef __cplusplus
  8140   8167   }  /* End of the 'extern "C"' block */
  8141   8168   #endif
  8142   8169   #endif /* _SQLITE3_H_ */

Changes to src/sqliteInt.h.

  3298   3298   # define sqlite3Toupper(x)  ((x)&~(sqlite3CtypeMap[(unsigned char)(x)]&0x20))
  3299   3299   # define sqlite3Isspace(x)   (sqlite3CtypeMap[(unsigned char)(x)]&0x01)
  3300   3300   # define sqlite3Isalnum(x)   (sqlite3CtypeMap[(unsigned char)(x)]&0x06)
  3301   3301   # define sqlite3Isalpha(x)   (sqlite3CtypeMap[(unsigned char)(x)]&0x02)
  3302   3302   # define sqlite3Isdigit(x)   (sqlite3CtypeMap[(unsigned char)(x)]&0x04)
  3303   3303   # define sqlite3Isxdigit(x)  (sqlite3CtypeMap[(unsigned char)(x)]&0x08)
  3304   3304   # define sqlite3Tolower(x)   (sqlite3UpperToLower[(unsigned char)(x)])
         3305  +# define sqlite3Isquote(x)   (sqlite3CtypeMap[(unsigned char)(x)]&0x80)
  3305   3306   #else
  3306   3307   # define sqlite3Toupper(x)   toupper((unsigned char)(x))
  3307   3308   # define sqlite3Isspace(x)   isspace((unsigned char)(x))
  3308   3309   # define sqlite3Isalnum(x)   isalnum((unsigned char)(x))
  3309   3310   # define sqlite3Isalpha(x)   isalpha((unsigned char)(x))
  3310   3311   # define sqlite3Isdigit(x)   isdigit((unsigned char)(x))
  3311   3312   # define sqlite3Isxdigit(x)  isxdigit((unsigned char)(x))
  3312   3313   # define sqlite3Tolower(x)   tolower((unsigned char)(x))
         3314  +# define sqlite3Isquote(x)   ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`')
  3313   3315   #endif
  3314   3316   #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
  3315   3317   int sqlite3IsIdChar(u8);
  3316   3318   #endif
  3317   3319   
  3318   3320   /*
  3319   3321   ** Internal function prototypes
................................................................................
  3429   3431     void sqlite3TreeViewSelect(TreeView*, const Select*, u8);
  3430   3432     void sqlite3TreeViewWith(TreeView*, const With*, u8);
  3431   3433   #endif
  3432   3434   
  3433   3435   
  3434   3436   void sqlite3SetString(char **, sqlite3*, const char*);
  3435   3437   void sqlite3ErrorMsg(Parse*, const char*, ...);
  3436         -int sqlite3Dequote(char*);
         3438  +void sqlite3Dequote(char*);
  3437   3439   void sqlite3TokenInit(Token*,char*);
  3438   3440   int sqlite3KeywordCode(const unsigned char*, int);
  3439   3441   int sqlite3RunParser(Parse*, const char*, char **);
  3440   3442   void sqlite3FinishCoding(Parse*);
  3441   3443   int sqlite3GetTempReg(Parse*);
  3442   3444   void sqlite3ReleaseTempReg(Parse*,int);
  3443   3445   int sqlite3GetTempRange(Parse*,int);

Changes to src/test1.c.

  2355   2355     }
  2356   2356     pSnapshot = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
  2357   2357     sqlite3_snapshot_free(pSnapshot);
  2358   2358     return TCL_OK;
  2359   2359   }
  2360   2360   #endif /* SQLITE_ENABLE_SNAPSHOT */
  2361   2361   
         2362  +#ifdef SQLITE_ENABLE_SNAPSHOT
         2363  +/*
         2364  +** Usage: sqlite3_snapshot_cmp SNAPSHOT1 SNAPSHOT2
         2365  +*/
         2366  +static int test_snapshot_cmp(
         2367  +  void * clientData,
         2368  +  Tcl_Interp *interp,
         2369  +  int objc,
         2370  +  Tcl_Obj *CONST objv[]
         2371  +){
         2372  +  int res;
         2373  +  sqlite3_snapshot *p1;
         2374  +  sqlite3_snapshot *p2;
         2375  +  if( objc!=3 ){
         2376  +    Tcl_WrongNumArgs(interp, 1, objv, "SNAPSHOT1 SNAPSHOT2");
         2377  +    return TCL_ERROR;
         2378  +  }
         2379  +  p1 = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
         2380  +  p2 = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[2]));
         2381  +  res = sqlite3_snapshot_cmp(p1, p2);
         2382  +  Tcl_SetObjResult(interp, Tcl_NewIntObj(res));
         2383  +  return TCL_OK;
         2384  +}
         2385  +#endif /* SQLITE_ENABLE_SNAPSHOT */
         2386  +
  2362   2387   /*
  2363   2388   ** Usage:  sqlite3_next_stmt  DB  STMT
  2364   2389   **
  2365   2390   ** Return the next statment in sequence after STMT.
  2366   2391   */
  2367   2392   static int test_next_stmt(
  2368   2393     void * clientData,
................................................................................
  7245   7270        { "sqlite3_config_sqllog",         test_config_sqllog,   0 },
  7246   7271   #endif
  7247   7272        { "vfs_current_time_int64",           vfsCurrentTimeInt64,   0 },
  7248   7273   #ifdef SQLITE_ENABLE_SNAPSHOT
  7249   7274        { "sqlite3_snapshot_get", test_snapshot_get, 0 },
  7250   7275        { "sqlite3_snapshot_open", test_snapshot_open, 0 },
  7251   7276        { "sqlite3_snapshot_free", test_snapshot_free, 0 },
         7277  +     { "sqlite3_snapshot_cmp", test_snapshot_cmp, 0 },
  7252   7278   #endif
  7253   7279     };
  7254   7280     static int bitmask_size = sizeof(Bitmask)*8;
  7255   7281     static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
  7256   7282     int i;
  7257   7283     extern int sqlite3_sync_count, sqlite3_fullsync_count;
  7258   7284     extern int sqlite3_opentemp_count;

Changes to src/tokenize.c.

   579    579       /* If the pParse->declareVtab flag is set, do not delete any table 
   580    580       ** structure built up in pParse->pNewTable. The calling code (see vtab.c)
   581    581       ** will take responsibility for freeing the Table structure.
   582    582       */
   583    583       sqlite3DeleteTable(db, pParse->pNewTable);
   584    584     }
   585    585   
   586         -  sqlite3WithDelete(db, pParse->pWithToFree);
          586  +  if( pParse->pWithToFree ) sqlite3WithDelete(db, pParse->pWithToFree);
   587    587     sqlite3DeleteTrigger(db, pParse->pNewTrigger);
   588    588     for(i=pParse->nzVar-1; i>=0; i--) sqlite3DbFree(db, pParse->azVar[i]);
   589    589     sqlite3DbFree(db, pParse->azVar);
   590    590     while( pParse->pAinc ){
   591    591       AutoincInfo *p = pParse->pAinc;
   592    592       pParse->pAinc = p->pNext;
   593    593       sqlite3DbFree(db, p);

Changes to src/util.c.

   238    238   ** dequoted string, exclusive of the zero terminator, if dequoting does
   239    239   ** occur.
   240    240   **
   241    241   ** 2002-Feb-14: This routine is extended to remove MS-Access style
   242    242   ** brackets from around identifiers.  For example:  "[a-b-c]" becomes
   243    243   ** "a-b-c".
   244    244   */
   245         -int sqlite3Dequote(char *z){
          245  +void sqlite3Dequote(char *z){
   246    246     char quote;
   247    247     int i, j;
   248         -  if( z==0 ) return -1;
          248  +  if( z==0 ) return;
   249    249     quote = z[0];
   250         -  switch( quote ){
   251         -    case '\'':  break;
   252         -    case '"':   break;
   253         -    case '`':   break;                /* For MySQL compatibility */
   254         -    case '[':   quote = ']';  break;  /* For MS SqlServer compatibility */
   255         -    default:    return -1;
   256         -  }
          250  +  if( !sqlite3Isquote(quote) ) return;
          251  +  if( quote=='[' ) quote = ']';
   257    252     for(i=1, j=0;; i++){
   258    253       assert( z[i] );
   259    254       if( z[i]==quote ){
   260    255         if( z[i+1]==quote ){
   261    256           z[j++] = quote;
   262    257           i++;
   263    258         }else{
................................................................................
   264    259           break;
   265    260         }
   266    261       }else{
   267    262         z[j++] = z[i];
   268    263       }
   269    264     }
   270    265     z[j] = 0;
   271         -  return j;
   272    266   }
   273    267   
   274    268   /*
   275    269   ** Generate a Token object from a string
   276    270   */
   277    271   void sqlite3TokenInit(Token *p, char *z){
   278    272     p->z = z;

Changes to src/wal.c.

  3395   3395   }
  3396   3396   
  3397   3397   /* Try to open on pSnapshot when the next read-transaction starts
  3398   3398   */
  3399   3399   void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot){
  3400   3400     pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
  3401   3401   }
         3402  +
         3403  +/* 
         3404  +** Return a +ve value if snapshot p1 is newer than p2. A -ve value if
         3405  +** p1 is older than p2 and zero if p1 and p2 are the same snapshot.
         3406  +*/
         3407  +int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){
         3408  +  WalIndexHdr *pHdr1 = (WalIndexHdr*)p1;
         3409  +  WalIndexHdr *pHdr2 = (WalIndexHdr*)p2;
         3410  +
         3411  +  /* aSalt[0] is a copy of the value stored in the wal file header. It
         3412  +  ** is incremented each time the wal file is restarted.  */
         3413  +  if( pHdr1->aSalt[0]<pHdr2->aSalt[0] ) return -1;
         3414  +  if( pHdr1->aSalt[0]>pHdr2->aSalt[0] ) return +1;
         3415  +  if( pHdr1->mxFrame<pHdr2->mxFrame ) return -1;
         3416  +  if( pHdr1->mxFrame>pHdr2->mxFrame ) return +1;
         3417  +  return 0;
         3418  +}
  3402   3419   #endif /* SQLITE_ENABLE_SNAPSHOT */
  3403   3420   
  3404   3421   #ifdef SQLITE_ENABLE_ZIPVFS
  3405   3422   /*
  3406   3423   ** If the argument is not NULL, it points to a Wal object that holds a
  3407   3424   ** read-lock. This function returns the database page-size if it is known,
  3408   3425   ** or zero if it is not (or if pWal is NULL).

Changes to src/whereexpr.c.

  1278   1278     Bitmask mask = 0;
  1279   1279     if( p==0 ) return 0;
  1280   1280     if( p->op==TK_COLUMN ){
  1281   1281       mask = sqlite3WhereGetMask(pMaskSet, p->iTable);
  1282   1282       return mask;
  1283   1283     }
  1284   1284     mask = sqlite3WhereExprUsage(pMaskSet, p->pRight);
  1285         -  mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft);
         1285  +  if( p->pLeft ) mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft);
  1286   1286     if( ExprHasProperty(p, EP_xIsSelect) ){
  1287   1287       mask |= exprSelectUsage(pMaskSet, p->x.pSelect);
  1288         -  }else{
         1288  +  }else if( p->x.pList ){
  1289   1289       mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList);
  1290   1290     }
  1291   1291     return mask;
  1292   1292   }
  1293   1293   Bitmask sqlite3WhereExprListUsage(WhereMaskSet *pMaskSet, ExprList *pList){
  1294   1294     int i;
  1295   1295     Bitmask mask = 0;

Changes to test/snapshot.test.

   360    360     db2 close
   361    361     sqlite3 db2 test.db 
   362    362     db2 eval "BEGIN"
   363    363     list [catch {sqlite3_snapshot_open db2 main $::snapshot} msg] $msg
   364    364   } {1 SQLITE_ERROR}
   365    365   
   366    366   sqlite3_snapshot_free $snapshot
          367  +
          368  +#-------------------------------------------------------------------------
          369  +# The following tests investigate the sqlite3_snapshot_cmp() API.
          370  +#
          371  +
          372  +# Compare snapshots $p1 and $p2, checking that the result is $r.
          373  +#
          374  +proc do_snapshot_cmp_test {tn p1 p2 r} {
          375  +  uplevel [list do_test $tn.1 [list sqlite3_snapshot_cmp $p1 $p2] $r]
          376  +  uplevel [list do_test $tn.2 [list sqlite3_snapshot_cmp $p2 $p1] [expr $r*-1]]
          377  +  uplevel [list do_test $tn.3 [list sqlite3_snapshot_cmp $p1 $p1] 0]
          378  +  uplevel [list do_test $tn.4 [list sqlite3_snapshot_cmp $p2 $p2] 0]
          379  +}
          380  +
          381  +catch { db2 close }
          382  +reset_db
          383  +
          384  +do_execsql_test 7.1 {
          385  +  PRAGMA journal_mode = wal;
          386  +  CREATE TABLE t1(x);
          387  +} wal
          388  +
          389  +do_test 7.1.2 {
          390  +  execsql { BEGIN ; PRAGMA application_id }
          391  +  set p1 [sqlite3_snapshot_get db main]
          392  +  execsql {
          393  +    INSERT INTO t1 VALUES(10);
          394  +    COMMIT;
          395  +  }
          396  +  execsql { BEGIN ; PRAGMA application_id }
          397  +  set p2 [sqlite3_snapshot_get db main]
          398  +  execsql COMMIT
          399  +} {}
          400  +
          401  +do_snapshot_cmp_test 7.1.3 $p1 $p2 -1
          402  +sqlite3_snapshot_free $p1
          403  +sqlite3_snapshot_free $p2
          404  +
          405  +do_execsql_test 7.2.1 {
          406  +  INSERT INTO t1 VALUES(11);
          407  +  INSERT INTO t1 VALUES(12);
          408  +  INSERT INTO t1 VALUES(13);
          409  +  BEGIN; 
          410  +    PRAGMA application_id;
          411  +} {0}
          412  +do_test 7.2.2 {
          413  +  set p1 [sqlite3_snapshot_get db main]
          414  +  execsql {
          415  +    COMMIT;
          416  +    INSERT INTO t1 VALUES(14);
          417  +    PRAGMA wal_checkpoint;
          418  +    BEGIN;
          419  +      PRAGMA application_id;
          420  +  }
          421  +  set p2 [sqlite3_snapshot_get db main]
          422  +  execsql COMMIT
          423  +} {}
          424  +
          425  +do_snapshot_cmp_test 7.2.3 $p1 $p2 -1
          426  +sqlite3_snapshot_free $p2
          427  +
          428  +do_test 7.3.1 {
          429  +  execsql {
          430  +    INSERT INTO t1 VALUES(14);
          431  +    BEGIN;
          432  +      PRAGMA application_id;
          433  +  }
          434  +  set p2 [sqlite3_snapshot_get db main]
          435  +  execsql COMMIT
          436  +} {}
          437  +
          438  +do_snapshot_cmp_test 7.3.2 $p1 $p2 -1
          439  +sqlite3_snapshot_free $p1
          440  +sqlite3_snapshot_free $p2
   367    441   
   368    442   finish_test