/ Check-in [1e973f65]
Login

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

Overview
Comment:Merge bug fixes from trunk.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | apple-osx
Files: files | file ages | folders
SHA3-256: 1e973f65e8340a34eef9b9c4e064f69fc9c3995bd15e5c25777ab803160b73b4
User & Date: drh 2018-10-25 16:58:27
Context
2018-10-31
01:26
Merge fixes from trunk, especially rebustness against corrupt database files. check-in: 4b370c74 user: drh tags: apple-osx
2018-10-25
16:58
Merge bug fixes from trunk. check-in: 1e973f65 user: drh tags: apple-osx
14:15
In the WHERE-constraint propagation optimization, if there are duplicate constraint, make sure only one of them propagates. Proposed fix for ticket [cf5ed20fc8621b165]. check-in: 5d5b596f user: drh tags: trunk
2018-10-12
22:02
Fix the SQLITE_ENABLE_APPLE_SPI compile-time option. check-in: 6cb537bd user: drh tags: apple-osx
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/session/session_common.tcl.

    90     90     catch { S delete }
    91     91   
    92     92     if {$rc} {
    93     93       error $changeset
    94     94     }
    95     95     return $changeset
    96     96   }
           97  +
           98  +proc patchset_from_sql {sql {dbname main}} {
           99  +  set rc [catch {
          100  +    sqlite3session S db $dbname
          101  +    db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" {
          102  +      S attach $name
          103  +    }
          104  +    db eval $sql
          105  +    S patchset
          106  +  } patchset]
          107  +  catch { S delete }
          108  +
          109  +  if {$rc} {
          110  +    error $patchset
          111  +  }
          112  +  return $patchset
          113  +}
    97    114   
    98    115   proc do_then_apply_sql {sql {dbname main}} {
    99    116     proc xConflict args { return "OMIT" }
   100    117     set rc [catch {
   101    118       sqlite3session S db $dbname
   102    119       db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" {
   103    120         S attach $name

Added ext/session/sessioninvert.test.

            1  +# 2018 October 18
            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.
           12  +#
           13  +
           14  +if {![info exists testdir]} {
           15  +  set testdir [file join [file dirname [info script]] .. .. test]
           16  +} 
           17  +source [file join [file dirname [info script]] session_common.tcl]
           18  +source $testdir/tester.tcl
           19  +ifcapable !session {finish_test; return}
           20  +
           21  +set testprefix sessioninvert
           22  +
           23  +proc iter_invert {C} {
           24  +  set x [list]
           25  +  sqlite3session_foreach -invert c $C { lappend x $c }
           26  +  set x
           27  +}
           28  +
           29  +proc do_invert_test {tn sql {iter {}}} {
           30  +
           31  +  forcecopy test.db test.db2
           32  +  sqlite3 db2 test.db2
           33  +
           34  +  set C [changeset_from_sql $sql]
           35  +
           36  +  forcecopy test.db test.db3
           37  +  sqlite3 db3 test.db3
           38  +  uplevel [list do_test $tn.1 [list compare_db db db3] {}]
           39  +
           40  +  set I [sqlite3changeset_invert $C]
           41  +  sqlite3changeset_apply db $I {}
           42  +  uplevel [list do_test $tn.2 [list compare_db db db2] {}]
           43  +  
           44  +  sqlite3changeset_apply_v2 -invert db3 $C {}
           45  +  uplevel [list do_test $tn.3 [list compare_db db db3] {}]
           46  +
           47  +  if {$iter!=""} {
           48  +    uplevel [list do_test $tn.4 [list iter_invert $C] [list {*}$iter]]
           49  +  }
           50  +
           51  +  catch { db2 close }
           52  +  catch { db3 close }
           53  +}
           54  +
           55  +do_execsql_test 1.0 {
           56  +  CREATE TABLE t1(a PRIMARY KEY, b, c);
           57  +  CREATE TABLE t2(d, e, f, PRIMARY KEY(e, f));
           58  +
           59  +  INSERT INTO t1 VALUES(1, 'one', 'i');
           60  +  INSERT INTO t1 VALUES(2, 'two', 'ii');
           61  +  INSERT INTO t1 VALUES(3, 'three', 'iii');
           62  +  INSERT INTO t1 VALUES(4, 'four', 'iv');
           63  +  INSERT INTO t1 VALUES(5, 'five', 'v');
           64  +  INSERT INTO t1 VALUES(6, 'six', 'vi');
           65  +
           66  +  INSERT INTO t2 SELECT * FROM t1;
           67  +}
           68  +
           69  +do_invert_test 1.1 {
           70  +  INSERT INTO t1 VALUES(7, 'seven', 'vii');
           71  +} {
           72  +  {DELETE t1 0 X.. {i 7 t seven t vii} {}}
           73  +}
           74  +
           75  +do_invert_test 1.2 {
           76  +  DELETE FROM t1 WHERE a<4;
           77  +} {
           78  +  {INSERT t1 0 X.. {} {i 1 t one t i}}
           79  +  {INSERT t1 0 X.. {} {i 2 t two t ii}}
           80  +  {INSERT t1 0 X.. {} {i 3 t three t iii}}
           81  +}
           82  +
           83  +do_invert_test 1.3 {
           84  +  UPDATE t1 SET c=5;
           85  +} {
           86  +  {UPDATE t1 0 X.. {i 1 {} {} i 5} {{} {} {} {} t i}}
           87  +  {UPDATE t1 0 X.. {i 2 {} {} i 5} {{} {} {} {} t ii}}
           88  +  {UPDATE t1 0 X.. {i 3 {} {} i 5} {{} {} {} {} t iii}}
           89  +  {UPDATE t1 0 X.. {i 4 {} {} i 5} {{} {} {} {} t iv}}
           90  +  {UPDATE t1 0 X.. {i 5 {} {} i 5} {{} {} {} {} t v}}
           91  +  {UPDATE t1 0 X.. {i 6 {} {} i 5} {{} {} {} {} t vi}}
           92  +}
           93  +
           94  +do_invert_test 1.4 {
           95  +  UPDATE t1 SET b = a+1 WHERE a%2;
           96  +  DELETE FROM t2;
           97  +  INSERT INTO t1 VALUES(10, 'ten', NULL);
           98  +}
           99  +
          100  +do_invert_test 1.5 {
          101  +  UPDATE t2 SET d = d-1;
          102  +} {
          103  +  {UPDATE t2 0 .XX {i 2 t three t iii} {i 3 {} {} {} {}}}
          104  +  {UPDATE t2 0 .XX {i 1 t two t ii} {i 2 {} {} {} {}}}
          105  +  {UPDATE t2 0 .XX {i 5 t six t vi} {i 6 {} {} {} {}}}
          106  +  {UPDATE t2 0 .XX {i 3 t four t iv} {i 4 {} {} {} {}}}
          107  +  {UPDATE t2 0 .XX {i 0 t one t i} {i 1 {} {} {} {}}}
          108  +  {UPDATE t2 0 .XX {i 4 t five t v} {i 5 {} {} {} {}}}
          109  +}
          110  +
          111  +do_execsql_test 2.0 { 
          112  +  ANALYZE;
          113  +  PRAGMA writable_schema = 1;
          114  +  DROP TABLE IF EXISTS sqlite_stat4;
          115  +  SELECT * FROM sqlite_stat1;
          116  +} {
          117  +  t2 sqlite_autoindex_t2_1 {6 1 1} 
          118  +  t1 sqlite_autoindex_t1_1 {6 1}
          119  +}
          120  +
          121  +do_invert_test 2.1 {
          122  +  INSERT INTO sqlite_stat1 VALUES('t3', 'idx2', '1 2 3');
          123  +} {
          124  +  {DELETE sqlite_stat1 0 XX. {t t3 t idx2 t {1 2 3}} {}}
          125  +}
          126  +
          127  +do_invert_test 2.2 {
          128  +  DELETE FROM sqlite_stat1;
          129  +} {
          130  +  {INSERT sqlite_stat1 0 XX. {} {t t1 t sqlite_autoindex_t1_1 t {6 1}}}
          131  +  {INSERT sqlite_stat1 0 XX. {} {t t2 t sqlite_autoindex_t2_1 t {6 1 1}}}
          132  +}
          133  +
          134  +do_invert_test 2.3 {
          135  +  UPDATE sqlite_stat1 SET stat = 'hello world';
          136  +}
          137  +
          138  +do_test 3.0 {
          139  +  forcecopy test.db test.db2
          140  +  sqlite3 db2 test.db2
          141  +  set P [patchset_from_sql {
          142  +    INSERT INTO t2 VALUES(1, 2, 3);
          143  +    DELETE FROM t2 WHERE d = 3;
          144  +  }]
          145  +
          146  +  list [catch { sqlite3changeset_apply_v2 -invert db2 $P {} } msg] $msg
          147  +} {1 SQLITE_CORRUPT}
          148  +
          149  +do_test 3.1 {
          150  +  list [catch { sqlite3session_foreach -invert db2 $P {} } msg] $msg
          151  +} {1 SQLITE_CORRUPT}
          152  +
          153  +do_test 3.2 {
          154  +  sqlite3changeset_apply_v2 db2 $P {} 
          155  +  compare_db db db2
          156  +} {}
          157  +
          158  +
          159  +finish_test

Changes to ext/session/sqlite3session.c.

    83     83   /*
    84     84   ** Structure for changeset iterators.
    85     85   */
    86     86   struct sqlite3_changeset_iter {
    87     87     SessionInput in;                /* Input buffer or stream */
    88     88     SessionBuffer tblhdr;           /* Buffer to hold apValue/zTab/abPK/ */
    89     89     int bPatchset;                  /* True if this is a patchset */
           90  +  int bInvert;                    /* True to invert changeset */
    90     91     int rc;                         /* Iterator error code */
    91     92     sqlite3_stmt *pConflict;        /* Points to conflicting row, if any */
    92     93     char *zTab;                     /* Current table */
    93     94     int nCol;                       /* Number of columns in zTab */
    94     95     int op;                         /* Current operation */
    95     96     int bIndirect;                  /* True if current change was indirect */
    96     97     u8 *abPK;                       /* Primary key array */
................................................................................
  1789   1790   **
  1790   1791   ** If successful, return zero. Otherwise, if an OOM condition is encountered,
  1791   1792   ** set *pRc to SQLITE_NOMEM and return non-zero.
  1792   1793   */
  1793   1794   static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){
  1794   1795     if( *pRc==SQLITE_OK && p->nAlloc-p->nBuf<nByte ){
  1795   1796       u8 *aNew;
  1796         -    int nNew = p->nAlloc ? p->nAlloc : 128;
         1797  +    i64 nNew = p->nAlloc ? p->nAlloc : 128;
  1797   1798       do {
  1798   1799         nNew = nNew*2;
  1799         -    }while( nNew<(p->nBuf+nByte) );
         1800  +    }while( (nNew-p->nBuf)<nByte );
  1800   1801   
  1801         -    aNew = (u8 *)sqlite3_realloc(p->aBuf, nNew);
         1802  +    aNew = (u8 *)sqlite3_realloc64(p->aBuf, nNew);
  1802   1803       if( 0==aNew ){
  1803   1804         *pRc = SQLITE_NOMEM;
  1804   1805       }else{
  1805   1806         p->aBuf = aNew;
  1806   1807         p->nAlloc = nNew;
  1807   1808       }
  1808   1809     }
................................................................................
  2536   2537   ** Do the work for either sqlite3changeset_start() or start_strm().
  2537   2538   */
  2538   2539   static int sessionChangesetStart(
  2539   2540     sqlite3_changeset_iter **pp,    /* OUT: Changeset iterator handle */
  2540   2541     int (*xInput)(void *pIn, void *pData, int *pnData),
  2541   2542     void *pIn,
  2542   2543     int nChangeset,                 /* Size of buffer pChangeset in bytes */
  2543         -  void *pChangeset                /* Pointer to buffer containing changeset */
         2544  +  void *pChangeset,               /* Pointer to buffer containing changeset */
         2545  +  int bInvert                     /* True to invert changeset */
  2544   2546   ){
  2545   2547     sqlite3_changeset_iter *pRet;   /* Iterator to return */
  2546   2548     int nByte;                      /* Number of bytes to allocate for iterator */
  2547   2549   
  2548   2550     assert( xInput==0 || (pChangeset==0 && nChangeset==0) );
  2549   2551   
  2550   2552     /* Zero the output variable in case an error occurs. */
................................................................................
  2556   2558     if( !pRet ) return SQLITE_NOMEM;
  2557   2559     memset(pRet, 0, sizeof(sqlite3_changeset_iter));
  2558   2560     pRet->in.aData = (u8 *)pChangeset;
  2559   2561     pRet->in.nData = nChangeset;
  2560   2562     pRet->in.xInput = xInput;
  2561   2563     pRet->in.pIn = pIn;
  2562   2564     pRet->in.bEof = (xInput ? 0 : 1);
         2565  +  pRet->bInvert = bInvert;
  2563   2566   
  2564   2567     /* Populate the output variable and return success. */
  2565   2568     *pp = pRet;
  2566   2569     return SQLITE_OK;
  2567   2570   }
  2568   2571   
  2569   2572   /*
................................................................................
  2570   2573   ** Create an iterator used to iterate through the contents of a changeset.
  2571   2574   */
  2572   2575   int sqlite3changeset_start(
  2573   2576     sqlite3_changeset_iter **pp,    /* OUT: Changeset iterator handle */
  2574   2577     int nChangeset,                 /* Size of buffer pChangeset in bytes */
  2575   2578     void *pChangeset                /* Pointer to buffer containing changeset */
  2576   2579   ){
  2577         -  return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset);
         2580  +  return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, 0);
         2581  +}
         2582  +int sqlite3changeset_start_v2(
         2583  +  sqlite3_changeset_iter **pp,    /* OUT: Changeset iterator handle */
         2584  +  int nChangeset,                 /* Size of buffer pChangeset in bytes */
         2585  +  void *pChangeset,               /* Pointer to buffer containing changeset */
         2586  +  int flags
         2587  +){
         2588  +  int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT);
         2589  +  return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, bInvert);
  2578   2590   }
  2579   2591   
  2580   2592   /*
  2581   2593   ** Streaming version of sqlite3changeset_start().
  2582   2594   */
  2583   2595   int sqlite3changeset_start_strm(
  2584   2596     sqlite3_changeset_iter **pp,    /* OUT: Changeset iterator handle */
  2585   2597     int (*xInput)(void *pIn, void *pData, int *pnData),
  2586   2598     void *pIn
  2587   2599   ){
  2588         -  return sessionChangesetStart(pp, xInput, pIn, 0, 0);
         2600  +  return sessionChangesetStart(pp, xInput, pIn, 0, 0, 0);
         2601  +}
         2602  +int sqlite3changeset_start_v2_strm(
         2603  +  sqlite3_changeset_iter **pp,    /* OUT: Changeset iterator handle */
         2604  +  int (*xInput)(void *pIn, void *pData, int *pnData),
         2605  +  void *pIn,
         2606  +  int flags
         2607  +){
         2608  +  int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT);
         2609  +  return sessionChangesetStart(pp, xInput, pIn, 0, 0, bInvert);
  2589   2610   }
  2590   2611   
  2591   2612   /*
  2592   2613   ** If the SessionInput object passed as the only argument is a streaming
  2593   2614   ** object and the buffer is full, discard some data to free up space.
  2594   2615   */
  2595   2616   static void sessionDiscardData(SessionInput *pIn){
................................................................................
  2960   2981       if( sessionChangesetReadTblhdr(p) ) return p->rc;
  2961   2982       if( (p->rc = sessionInputBuffer(&p->in, 2)) ) return p->rc;
  2962   2983       p->in.iCurrent = p->in.iNext;
  2963   2984       if( p->in.iNext>=p->in.nData ) return SQLITE_DONE;
  2964   2985       op = p->in.aData[p->in.iNext++];
  2965   2986     }
  2966   2987   
  2967         -  if( p->zTab==0 ){
         2988  +  if( p->zTab==0 || (p->bPatchset && p->bInvert) ){
  2968   2989       /* The first record in the changeset is not a table header. Must be a
  2969   2990       ** corrupt changeset. */
  2970         -    assert( p->in.iNext==1 );
         2991  +    assert( p->in.iNext==1 || p->zTab );
  2971   2992       return (p->rc = SQLITE_CORRUPT_BKPT);
  2972   2993     }
  2973   2994   
  2974   2995     p->op = op;
  2975   2996     p->bIndirect = p->in.aData[p->in.iNext++];
  2976   2997     if( p->op!=SQLITE_UPDATE && p->op!=SQLITE_DELETE && p->op!=SQLITE_INSERT ){
  2977   2998       return (p->rc = SQLITE_CORRUPT_BKPT);
................................................................................
  2988   3009         nVal = p->nCol;
  2989   3010       }
  2990   3011       p->rc = sessionChangesetBufferRecord(&p->in, nVal, pnRec);
  2991   3012       if( p->rc!=SQLITE_OK ) return p->rc;
  2992   3013       *paRec = &p->in.aData[p->in.iNext];
  2993   3014       p->in.iNext += *pnRec;
  2994   3015     }else{
         3016  +    sqlite3_value **apOld = (p->bInvert ? &p->apValue[p->nCol] : p->apValue);
         3017  +    sqlite3_value **apNew = (p->bInvert ? p->apValue : &p->apValue[p->nCol]);
  2995   3018   
  2996   3019       /* If this is an UPDATE or DELETE, read the old.* record. */
  2997   3020       if( p->op!=SQLITE_INSERT && (p->bPatchset==0 || p->op==SQLITE_DELETE) ){
  2998   3021         u8 *abPK = p->bPatchset ? p->abPK : 0;
  2999         -      p->rc = sessionReadRecord(&p->in, p->nCol, abPK, p->apValue);
         3022  +      p->rc = sessionReadRecord(&p->in, p->nCol, abPK, apOld);
  3000   3023         if( p->rc!=SQLITE_OK ) return p->rc;
  3001   3024       }
  3002   3025   
  3003   3026       /* If this is an INSERT or UPDATE, read the new.* record. */
  3004   3027       if( p->op!=SQLITE_DELETE ){
  3005         -      p->rc = sessionReadRecord(&p->in, p->nCol, 0, &p->apValue[p->nCol]);
         3028  +      p->rc = sessionReadRecord(&p->in, p->nCol, 0, apNew);
  3006   3029         if( p->rc!=SQLITE_OK ) return p->rc;
  3007   3030       }
  3008   3031   
  3009         -    if( p->bPatchset && p->op==SQLITE_UPDATE ){
         3032  +    if( (p->bPatchset || p->bInvert) && p->op==SQLITE_UPDATE ){
  3010   3033         /* If this is an UPDATE that is part of a patchset, then all PK and
  3011   3034         ** modified fields are present in the new.* record. The old.* record
  3012   3035         ** is currently completely empty. This block shifts the PK fields from
  3013   3036         ** new.* to old.*, to accommodate the code that reads these arrays.  */
  3014   3037         for(i=0; i<p->nCol; i++){
  3015         -        assert( p->apValue[i]==0 );
         3038  +        assert( p->bPatchset==0 || p->apValue[i]==0 );
  3016   3039           if( p->abPK[i] ){
         3040  +          assert( p->apValue[i]==0 );
  3017   3041             p->apValue[i] = p->apValue[i+p->nCol];
  3018   3042             if( p->apValue[i]==0 ) return (p->rc = SQLITE_CORRUPT_BKPT);
  3019   3043             p->apValue[i+p->nCol] = 0;
  3020   3044           }
  3021   3045         }
         3046  +    }else if( p->bInvert ){
         3047  +      if( p->op==SQLITE_INSERT ) p->op = SQLITE_DELETE;
         3048  +      else if( p->op==SQLITE_DELETE ) p->op = SQLITE_INSERT;
  3022   3049       }
  3023   3050     }
  3024   3051   
  3025   3052     return SQLITE_ROW;
  3026   3053   }
  3027   3054   
  3028   3055   /*
................................................................................
  4178   4205     int rc = SQLITE_OK;
  4179   4206   
  4180   4207     while( pApply->constraints.nBuf ){
  4181   4208       sqlite3_changeset_iter *pIter2 = 0;
  4182   4209       SessionBuffer cons = pApply->constraints;
  4183   4210       memset(&pApply->constraints, 0, sizeof(SessionBuffer));
  4184   4211   
  4185         -    rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf);
         4212  +    rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf, 0);
  4186   4213       if( rc==SQLITE_OK ){
  4187   4214         int nByte = 2*pApply->nCol*sizeof(sqlite3_value*);
  4188   4215         int rc2;
  4189   4216         pIter2->bPatchset = bPatchset;
  4190   4217         pIter2->zTab = (char*)zTab;
  4191   4218         pIter2->nCol = pApply->nCol;
  4192   4219         pIter2->abPK = pApply->abPK;
................................................................................
  4432   4459       sqlite3_changeset_iter *p     /* Handle describing change and conflict */
  4433   4460     ),
  4434   4461     void *pCtx,                     /* First argument passed to xConflict */
  4435   4462     void **ppRebase, int *pnRebase,
  4436   4463     int flags
  4437   4464   ){
  4438   4465     sqlite3_changeset_iter *pIter;  /* Iterator to skip through changeset */  
  4439         -  int rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
         4466  +  int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
         4467  +  int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset,bInverse);
  4440   4468     if( rc==SQLITE_OK ){
  4441   4469       rc = sessionChangesetApply(
  4442   4470           db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
  4443   4471       );
  4444   4472     }
  4445   4473     return rc;
  4446   4474   }
................................................................................
  4489   4517       sqlite3_changeset_iter *p     /* Handle describing change and conflict */
  4490   4518     ),
  4491   4519     void *pCtx,                     /* First argument passed to xConflict */
  4492   4520     void **ppRebase, int *pnRebase,
  4493   4521     int flags
  4494   4522   ){
  4495   4523     sqlite3_changeset_iter *pIter;  /* Iterator to skip through changeset */  
  4496         -  int rc = sqlite3changeset_start_strm(&pIter, xInput, pIn);
         4524  +  int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
         4525  +  int rc = sessionChangesetStart(&pIter, xInput, pIn, 0, 0, bInverse);
  4497   4526     if( rc==SQLITE_OK ){
  4498   4527       rc = sessionChangesetApply(
  4499   4528           db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
  4500   4529       );
  4501   4530     }
  4502   4531     return rc;
  4503   4532   }

Changes to ext/session/sqlite3session.h.

   469    469   ** [sqlite3changeset_invert()] functions, all changes within the changeset 
   470    470   ** that apply to a single table are grouped together. This means that when 
   471    471   ** an application iterates through a changeset using an iterator created by 
   472    472   ** this function, all changes that relate to a single table are visited 
   473    473   ** consecutively. There is no chance that the iterator will visit a change 
   474    474   ** the applies to table X, then one for table Y, and then later on visit 
   475    475   ** another change for table X.
          476  +**
          477  +** The behavior of sqlite3changeset_start_v2() and its streaming equivalent
          478  +** may be modified by passing a combination of
          479  +** [SQLITE_CHANGESETSTART_INVERT | supported flags] as the 4th parameter.
          480  +**
          481  +** Note that the sqlite3changeset_start_v2() API is still <b>experimental</b>
          482  +** and therefore subject to change.
   476    483   */
   477    484   int sqlite3changeset_start(
   478    485     sqlite3_changeset_iter **pp,    /* OUT: New changeset iterator handle */
   479    486     int nChangeset,                 /* Size of changeset blob in bytes */
   480    487     void *pChangeset                /* Pointer to blob containing changeset */
   481    488   );
          489  +int sqlite3changeset_start_v2(
          490  +  sqlite3_changeset_iter **pp,    /* OUT: New changeset iterator handle */
          491  +  int nChangeset,                 /* Size of changeset blob in bytes */
          492  +  void *pChangeset,               /* Pointer to blob containing changeset */
          493  +  int flags                       /* SESSION_CHANGESETSTART_* flags */
          494  +);
          495  +
          496  +/*
          497  +** CAPI3REF: Flags for sqlite3changeset_start_v2
          498  +**
          499  +** The following flags may passed via the 4th parameter to
          500  +** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]:
          501  +**
          502  +** <dt>SQLITE_CHANGESETAPPLY_INVERT <dd>
          503  +**   Invert the changeset while iterating through it. This is equivalent to
          504  +**   inverting a changeset using sqlite3changeset_invert() before applying it.
          505  +**   It is an error to specify this flag with a patchset.
          506  +*/
          507  +#define SQLITE_CHANGESETSTART_INVERT        0x0002
   482    508   
   483    509   
   484    510   /*
   485    511   ** CAPI3REF: Advance A Changeset Iterator
   486    512   ** METHOD: sqlite3_changeset_iter
   487    513   **
   488    514   ** This function may only be used with iterators created by function
................................................................................
  1129   1155     int(*xConflict)(
  1130   1156       void *pCtx,                   /* Copy of sixth arg to _apply() */
  1131   1157       int eConflict,                /* DATA, MISSING, CONFLICT, CONSTRAINT */
  1132   1158       sqlite3_changeset_iter *p     /* Handle describing change and conflict */
  1133   1159     ),
  1134   1160     void *pCtx,                     /* First argument passed to xConflict */
  1135   1161     void **ppRebase, int *pnRebase, /* OUT: Rebase data */
  1136         -  int flags                       /* Combination of SESSION_APPLY_* flags */
         1162  +  int flags                       /* SESSION_CHANGESETAPPLY_* flags */
  1137   1163   );
  1138   1164   
  1139   1165   /*
  1140   1166   ** CAPI3REF: Flags for sqlite3changeset_apply_v2
  1141   1167   **
  1142   1168   ** The following flags may passed via the 9th parameter to
  1143   1169   ** [sqlite3changeset_apply_v2] and [sqlite3changeset_apply_v2_strm]:
................................................................................
  1147   1173   **   Usually, the sessions module encloses all operations performed by
  1148   1174   **   a single call to apply_v2() or apply_v2_strm() in a [SAVEPOINT]. The
  1149   1175   **   SAVEPOINT is committed if the changeset or patchset is successfully
  1150   1176   **   applied, or rolled back if an error occurs. Specifying this flag
  1151   1177   **   causes the sessions module to omit this savepoint. In this case, if the
  1152   1178   **   caller has an open transaction or savepoint when apply_v2() is called, 
  1153   1179   **   it may revert the partially applied changeset by rolling it back.
         1180  +**
         1181  +** <dt>SQLITE_CHANGESETAPPLY_INVERT <dd>
         1182  +**   Invert the changeset before applying it. This is equivalent to inverting
         1183  +**   a changeset using sqlite3changeset_invert() before applying it. It is
         1184  +**   an error to specify this flag with a patchset.
  1154   1185   */
  1155   1186   #define SQLITE_CHANGESETAPPLY_NOSAVEPOINT   0x0001
         1187  +#define SQLITE_CHANGESETAPPLY_INVERT        0x0002
  1156   1188   
  1157   1189   /* 
  1158   1190   ** CAPI3REF: Constants Passed To The Conflict Handler
  1159   1191   **
  1160   1192   ** Values that may be passed as the second argument to a conflict-handler.
  1161   1193   **
  1162   1194   ** <dl>
................................................................................
  1541   1573     int (*xOutput)(void *pOut, const void *pData, int nData),
  1542   1574     void *pOut
  1543   1575   );
  1544   1576   int sqlite3changeset_start_strm(
  1545   1577     sqlite3_changeset_iter **pp,
  1546   1578     int (*xInput)(void *pIn, void *pData, int *pnData),
  1547   1579     void *pIn
         1580  +);
         1581  +int sqlite3changeset_start_v2_strm(
         1582  +  sqlite3_changeset_iter **pp,
         1583  +  int (*xInput)(void *pIn, void *pData, int *pnData),
         1584  +  void *pIn,
         1585  +  int flags
  1548   1586   );
  1549   1587   int sqlite3session_changeset_strm(
  1550   1588     sqlite3_session *pSession,
  1551   1589     int (*xOutput)(void *pOut, const void *pData, int nData),
  1552   1590     void *pOut
  1553   1591   );
  1554   1592   int sqlite3session_patchset_strm(

Changes to ext/session/test_session.c.

   733    733     int nRebase = 0;
   734    734     int flags = 0;                  /* Flags for apply_v2() */
   735    735   
   736    736     memset(&sStr, 0, sizeof(sStr));
   737    737     sStr.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
   738    738   
   739    739     /* Check for the -nosavepoint flag */
   740         -  if( bV2 && objc>1 ){
   741         -    const char *z1 = Tcl_GetString(objv[1]);
   742         -    int n = strlen(z1);
   743         -    if( n>1 && n<=12 && 0==sqlite3_strnicmp("-nosavepoint", z1, n) ){
   744         -      flags = SQLITE_CHANGESETAPPLY_NOSAVEPOINT;
   745         -      objc--;
   746         -      objv++;
          740  +  if( bV2 ){
          741  +    if( objc>1 ){
          742  +      const char *z1 = Tcl_GetString(objv[1]);
          743  +      int n = strlen(z1);
          744  +      if( n>1 && n<=12 && 0==sqlite3_strnicmp("-nosavepoint", z1, n) ){
          745  +        flags |= SQLITE_CHANGESETAPPLY_NOSAVEPOINT;
          746  +        objc--;
          747  +        objv++;
          748  +      }
          749  +    }
          750  +    if( objc>1 ){
          751  +      const char *z1 = Tcl_GetString(objv[1]);
          752  +      int n = strlen(z1);
          753  +      if( n>1 && n<=7 && 0==sqlite3_strnicmp("-invert", z1, n) ){
          754  +        flags |= SQLITE_CHANGESETAPPLY_INVERT;
          755  +        objc--;
          756  +        objv++;
          757  +      }
   747    758       }
   748    759     }
   749    760   
   750    761     if( objc!=4 && objc!=5 ){
   751    762       const char *zMsg;
   752    763       if( bV2 ){
   753         -      zMsg = "?-nosavepoint? DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?";
          764  +      zMsg = "?-nosavepoint? ?-inverse? "
          765  +        "DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?";
   754    766       }else{
   755    767         zMsg = "DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?";
   756    768       }
   757    769       Tcl_WrongNumArgs(interp, 1, objv, zMsg);
   758    770       return TCL_ERROR;
   759    771     }
   760    772     if( 0==Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &info) ){
................................................................................
   965    977     int nChangeset;
   966    978     sqlite3_changeset_iter *pIter;
   967    979     int rc;
   968    980     Tcl_Obj *pVarname;
   969    981     Tcl_Obj *pCS;
   970    982     Tcl_Obj *pScript;
   971    983     int isCheckNext = 0;
          984  +  int isInvert = 0;
   972    985   
   973    986     TestStreamInput sStr;
   974    987     memset(&sStr, 0, sizeof(sStr));
   975    988   
   976         -  if( objc>1 ){
          989  +  while( objc>1 ){
   977    990       char *zOpt = Tcl_GetString(objv[1]);
   978         -    isCheckNext = (strcmp(zOpt, "-next")==0);
          991  +    int nOpt = strlen(zOpt);
          992  +    if( zOpt[0]!='-' ) break;
          993  +    if( nOpt<=7 && 0==sqlite3_strnicmp(zOpt, "-invert", nOpt) ){
          994  +      isInvert = 1;
          995  +    }else
          996  +    if( nOpt<=5 && 0==sqlite3_strnicmp(zOpt, "-next", nOpt) ){
          997  +      isCheckNext = 1;
          998  +    }else{
          999  +      break;
         1000  +    }
         1001  +    objv++;
         1002  +    objc--;
   979   1003     }
   980         -  if( objc!=4+isCheckNext ){
   981         -    Tcl_WrongNumArgs(interp, 1, objv, "?-next? VARNAME CHANGESET SCRIPT");
         1004  +  if( objc!=4 ){
         1005  +    Tcl_WrongNumArgs(
         1006  +        interp, 1, objv, "?-next? ?-invert? VARNAME CHANGESET SCRIPT");
   982   1007       return TCL_ERROR;
   983   1008     }
   984   1009   
   985         -  pVarname = objv[1+isCheckNext];
   986         -  pCS = objv[2+isCheckNext];
   987         -  pScript = objv[3+isCheckNext];
         1010  +  pVarname = objv[1];
         1011  +  pCS = objv[2];
         1012  +  pScript = objv[3];
   988   1013   
   989   1014     pChangeset = (void *)Tcl_GetByteArrayFromObj(pCS, &nChangeset);
   990   1015     sStr.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR);
   991         -  if( sStr.nStream==0 ){
   992         -    rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
         1016  +  if( isInvert ){
         1017  +    int f = SQLITE_CHANGESETSTART_INVERT;
         1018  +    if( sStr.nStream==0 ){
         1019  +      rc = sqlite3changeset_start_v2(&pIter, nChangeset, pChangeset, f);
         1020  +    }else{
         1021  +      void *pCtx = (void*)&sStr;
         1022  +      sStr.aData = (unsigned char*)pChangeset;
         1023  +      sStr.nData = nChangeset;
         1024  +      rc = sqlite3changeset_start_v2_strm(&pIter, testStreamInput, pCtx, f);
         1025  +    }
   993   1026     }else{
   994         -    sStr.aData = (unsigned char*)pChangeset;
   995         -    sStr.nData = nChangeset;
   996         -    rc = sqlite3changeset_start_strm(&pIter, testStreamInput, (void*)&sStr);
         1027  +    if( sStr.nStream==0 ){
         1028  +      rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
         1029  +    }else{
         1030  +      sStr.aData = (unsigned char*)pChangeset;
         1031  +      sStr.nData = nChangeset;
         1032  +      rc = sqlite3changeset_start_strm(&pIter, testStreamInput, (void*)&sStr);
         1033  +    }
   997   1034     }
   998   1035     if( rc!=SQLITE_OK ){
   999   1036       return test_session_error(interp, rc, 0);
  1000   1037     }
  1001   1038   
  1002   1039     while( SQLITE_ROW==sqlite3changeset_next(pIter) ){
  1003   1040       int nCol;                     /* Number of columns in table */

Changes to src/ctime.c.

   230    230     "ENABLE_FTS3_TOKENIZER",
   231    231   #endif
   232    232   #if SQLITE_ENABLE_FTS4
   233    233     "ENABLE_FTS4",
   234    234   #endif
   235    235   #if SQLITE_ENABLE_FTS5
   236    236     "ENABLE_FTS5",
          237  +#endif
          238  +#if SQLITE_ENABLE_GEOPOLY
          239  +  "ENABLE_GEOPOLY",
   237    240   #endif
   238    241   #if SQLITE_ENABLE_HIDDEN_COLUMNS
   239    242     "ENABLE_HIDDEN_COLUMNS",
   240    243   #endif
   241    244   #if SQLITE_ENABLE_ICU
   242    245     "ENABLE_ICU",
   243    246   #endif

Changes to src/select.c.

  4070   4070   #endif
  4071   4071   
  4072   4072     return 1;
  4073   4073   }
  4074   4074   #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
  4075   4075   
  4076   4076   /*
  4077         -** A structure to keep track of all of the column values that fixed to
         4077  +** A structure to keep track of all of the column values that are fixed to
  4078   4078   ** a known value due to WHERE clause constraints of the form COLUMN=VALUE.
  4079   4079   */
  4080   4080   typedef struct WhereConst WhereConst;
  4081   4081   struct WhereConst {
  4082   4082     Parse *pParse;   /* Parsing context */
  4083   4083     int nConst;      /* Number for COLUMN=CONSTANT terms */
  4084   4084     int nChng;       /* Number of times a constant is propagated */
  4085   4085     Expr **apExpr;   /* [i*2] is COLUMN and [i*2+1] is VALUE */
  4086   4086   };
  4087   4087   
  4088   4088   /*
  4089         -** Add a new entry to the pConst object
         4089  +** Add a new entry to the pConst object.  Except, do not add duplicate
         4090  +** pColumn entires.
  4090   4091   */
  4091   4092   static void constInsert(
  4092         -  WhereConst *pConst,
  4093         -  Expr *pColumn,
  4094         -  Expr *pValue
         4093  +  WhereConst *pConst,      /* The WhereConst into which we are inserting */
         4094  +  Expr *pColumn,           /* The COLUMN part of the constraint */
         4095  +  Expr *pValue             /* The VALUE part of the constraint */
  4095   4096   ){
         4097  +  int i;
         4098  +  assert( pColumn->op==TK_COLUMN );
         4099  +
         4100  +  /* 2018-10-25 ticket [cf5ed20f]
         4101  +  ** Make sure the same pColumn is not inserted more than once */
         4102  +  for(i=0; i<pConst->nConst; i++){
         4103  +    const Expr *pExpr = pConst->apExpr[i*2];
         4104  +    assert( pExpr->op==TK_COLUMN );
         4105  +    if( pExpr->iTable==pColumn->iTable
         4106  +     && pExpr->iColumn==pColumn->iColumn
         4107  +    ){
         4108  +      return;  /* Already present.  Return without doing anything. */
         4109  +    }
         4110  +  }
  4096   4111   
  4097   4112     pConst->nConst++;
  4098   4113     pConst->apExpr = sqlite3DbReallocOrFree(pConst->pParse->db, pConst->apExpr,
  4099   4114                            pConst->nConst*2*sizeof(Expr*));
  4100   4115     if( pConst->apExpr==0 ){
  4101   4116       pConst->nConst = 0;
  4102   4117     }else{

Changes to src/window.c.

   742    742   ** any SQL window functions, this function is a no-op. Otherwise, it 
   743    743   ** rewrites the SELECT statement so that window function xStep functions
   744    744   ** are invoked in the correct order as described under "SELECT REWRITING"
   745    745   ** at the top of this file.
   746    746   */
   747    747   int sqlite3WindowRewrite(Parse *pParse, Select *p){
   748    748     int rc = SQLITE_OK;
   749         -  if( p->pWin ){
          749  +  if( p->pWin && p->pPrior==0 ){
   750    750       Vdbe *v = sqlite3GetVdbe(pParse);
   751    751       sqlite3 *db = pParse->db;
   752    752       Select *pSub = 0;             /* The subquery */
   753    753       SrcList *pSrc = p->pSrc;
   754    754       Expr *pWhere = p->pWhere;
   755    755       ExprList *pGroupBy = p->pGroupBy;
   756    756       Expr *pHaving = p->pHaving;

Changes to test/dbstatus.test.

   375    375     }
   376    376   }
   377    377   
   378    378   #-------------------------------------------------------------------------
   379    379   # The following tests focus on DBSTATUS_CACHE_USED_SHARED
   380    380   #
   381    381   ifcapable shared_cache {
   382         -  if {[permutation]=="memsys3"
          382  +  if {([permutation]=="memsys3"
   383    383         || [permutation]=="memsys5"
   384         -      || $::tcl_platform(os)=="Linux"} {
          384  +      || $::tcl_platform(os)=="Linux") && ![sqlite3 -has-codec]} {
   385    385       proc do_cacheused_test {tn db res} {
   386    386         set cu [sqlite3_db_status $db SQLITE_DBSTATUS_CACHE_USED 0]
   387    387         set pcu [sqlite3_db_status $db SQLITE_DBSTATUS_CACHE_USED_SHARED 0]
   388    388         set cu [lindex $cu 1]
   389    389         set pcu [lindex $pcu 1]
   390    390         uplevel [list do_test $tn [list list $cu $pcu] "#/$res/"]
   391    391       }

Changes to test/pragma3.test.

    11     11   # This file implements regression tests for SQLite library.
    12     12   #
    13     13   # This file implements tests for PRAGMA data_version command.
    14     14   #
    15     15   
    16     16   set testdir [file dirname $argv0]
    17     17   source $testdir/tester.tcl
    18         -do_not_use_codec
           18  +
           19  +if {[sqlite3 -has-codec]} {
           20  +  finish_test
           21  +  return
           22  +}
    19     23   
    20     24   do_execsql_test pragma3-100 {
    21     25     PRAGMA data_version;
    22     26   } {1}
    23     27   do_execsql_test pragma3-101 {
    24     28     PRAGMA temp.data_version;
    25     29   } {1}

Changes to test/shared.test.

  1137   1137   } {1 {no such table: t1}}
  1138   1138   do_test shared-$av-16.8 {
  1139   1139     file exists test1.db
  1140   1140   } {0}  ;# Verify that the database is in-memory
  1141   1141   
  1142   1142   # Shared cache on named memory databases attached to readonly connections.
  1143   1143   #
  1144         -do_test shared-$av-16.8.1 {
         1144  +if {![sqlite3 -has-codec]} {
         1145  +  do_test shared-$av-16.8.1 {
         1146  +    db1 close
         1147  +    db2 close
         1148  +  
         1149  +    sqlite3 db test1.db
         1150  +    db eval { 
         1151  +      CREATE TABLE yy(a, b);
         1152  +      INSERT INTO yy VALUES(77, 88);
         1153  +    }
         1154  +    db close
         1155  +  
         1156  +    sqlite3 db1 test1.db -uri 1 -readonly 1
         1157  +    sqlite3 db2 test2.db -uri 1 
         1158  +  
         1159  +    db1 eval { 
         1160  +      ATTACH 'file:mem?mode=memory&cache=shared' AS shared; 
         1161  +      CREATE TABLE shared.xx(a, b);
         1162  +      INSERT INTO xx VALUES(55, 66);
         1163  +    }
         1164  +    db2 eval { 
         1165  +      ATTACH 'file:mem?mode=memory&cache=shared' AS shared;
         1166  +      SELECT * FROM xx;
         1167  +    }
         1168  +  } {55 66}
         1169  +  
         1170  +  do_test shared-$av-16.8.2 { db1 eval { SELECT * FROM yy } } {77 88}
         1171  +  do_test shared-$av-16.8.3 { 
         1172  +    list [catch {db1 eval { INSERT INTO yy VALUES(1, 2) }} msg] $msg
         1173  +  } {1 {attempt to write a readonly database}}
         1174  +  
  1145   1175     db1 close
  1146   1176     db2 close
  1147         -
  1148         -  sqlite3 db test1.db
  1149         -  db eval { 
  1150         -    CREATE TABLE yy(a, b);
  1151         -    INSERT INTO yy VALUES(77, 88);
  1152         -  }
  1153         -  db close
  1154         -
  1155         -  sqlite3 db1 test1.db -uri 1 -readonly 1
  1156         -  sqlite3 db2 test2.db -uri 1 
  1157         -
  1158         -  db1 eval { 
  1159         -    ATTACH 'file:mem?mode=memory&cache=shared' AS shared; 
  1160         -    CREATE TABLE shared.xx(a, b);
  1161         -    INSERT INTO xx VALUES(55, 66);
  1162         -  }
  1163         -  db2 eval { 
  1164         -    ATTACH 'file:mem?mode=memory&cache=shared' AS shared;
  1165         -    SELECT * FROM xx;
  1166         -  }
  1167         -} {55 66}
  1168         -
  1169         -do_test shared-$av-16.8.2 { db1 eval { SELECT * FROM yy } } {77 88}
  1170         -do_test shared-$av-16.8.3 { 
  1171         -  list [catch {db1 eval { INSERT INTO yy VALUES(1, 2) }} msg] $msg
  1172         -} {1 {attempt to write a readonly database}}
  1173         -
  1174         -db1 close
  1175         -db2 close
         1177  +}
  1176   1178   
  1177   1179   }  ;# end of autovacuum on/off loop
  1178   1180   
  1179   1181   sqlite3_enable_shared_cache $::enable_shared_cache
  1180   1182   finish_test

Changes to test/whereL.test.

   106    106       FROM A,
   107    107            (SELECT id,yy,zz FROM C) subq,
   108    108            B
   109    109      WHERE A.id='1'
   110    110        AND A.id=subq.yy
   111    111        AND B.id=subq.zz;
   112    112   } {1}  
          113  +
          114  +# 2018-10-25: Ticket [cf5ed20f]
          115  +# Incorrect join result with duplicate WHERE clause constraint.
          116  +#
          117  +do_execsql_test 400 {
          118  +  CREATE TABLE x(a, b, c);
          119  +  CREATE TABLE y(a, b);
          120  +  INSERT INTO x VALUES (1, 0, 1);
          121  +  INSERT INTO y VALUES (1, 2);
          122  +  SELECT x.a FROM x JOIN y ON x.c = y.a WHERE x.b = 1 AND x.b = 1;
          123  +} {}
   113    124   
   114    125   finish_test

Changes to test/window1.test.

   544    544   do_execsql_test 12.110 {
   545    545     INSERT INTO t1 VALUES(6, 'F', 'three');
   546    546     INSERT INTO t1 VALUES(7, 'G', 'one');
   547    547     SELECT id, b, lead(c,1) OVER(ORDER BY c) AS x
   548    548       FROM t1 WHERE id>1
   549    549      ORDER BY b LIMIT 2;
   550    550   } {2 B two 3 C three}
          551  +
          552  +#-------------------------------------------------------------------------
          553  +
          554  +do_execsql_test 13.1 {
          555  +  DROP TABLE IF EXISTS t1;
          556  +  CREATE TABLE t1(a int, b int);
          557  +  INSERT INTO t1 VALUES(1,11);
          558  +  INSERT INTO t1 VALUES(2,12);
          559  +}
          560  +
          561  +do_execsql_test 13.2.1 {
          562  +  SELECT a, rank() OVER(ORDER BY b) FROM t1;
          563  +  SELECT a, rank() OVER(ORDER BY b DESC) FROM t1;
          564  +} {
          565  +  1 1   2 2   2 1   1 2
          566  +}
          567  +do_execsql_test 13.2.2 {
          568  +  SELECT a, rank() OVER(ORDER BY b) FROM t1
          569  +    UNION ALL
          570  +  SELECT a, rank() OVER(ORDER BY b DESC) FROM t1;
          571  +} {
          572  +  1 1   2 2   2 1   1 2
          573  +}
          574  +do_execsql_test 13.3 {
          575  +  SELECT a, rank() OVER(ORDER BY b) FROM t1
          576  +    UNION 
          577  +  SELECT a, rank() OVER(ORDER BY b DESC) FROM t1;
          578  +} {
          579  +  1 1   1 2   2 1   2 2  
          580  +}
          581  +
          582  +do_execsql_test 13.4 {
          583  +  SELECT a, rank() OVER(ORDER BY b) FROM t1
          584  +    EXCEPT 
          585  +  SELECT a, rank() OVER(ORDER BY b DESC) FROM t1;
          586  +} {
          587  +  1 1   2 2 
          588  +}
          589  +
          590  +do_execsql_test 13.5 {
          591  +  SELECT a, rank() OVER(ORDER BY b) FROM t1
          592  +    INTERSECT 
          593  +  SELECT a, rank() OVER(ORDER BY b DESC) FROM t1;
          594  +} {
          595  +}
   551    596   
   552    597   finish_test