/ Check-in [62325198]
Login

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

Overview
Comment:Merge latest trunk changes into this branch.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | exp-window-functions
Files: files | file ages | folders
SHA3-256:6232519899efc568465d8fcc9fcd79d46a2ce4ec05109d26d5eb1ebd239cd596
User & Date: dan 2018-05-25 09:36:27
Context
2018-05-25
20:30
Fix "RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING" window frame processing. check-in: b4e9c686 user: dan tags: exp-window-functions
09:36
Merge latest trunk changes into this branch. check-in: 62325198 user: dan tags: exp-window-functions
09:29
Fixes for "ROWS BETWEEN <expr> FOLLOWING AND <expr> FOLLOWING" and "ROWS BETWEEN <expr> FOLLOWING AND UNBOUNDED FOLLOWING" check-in: 5ac44872 user: dan tags: exp-window-functions
2018-05-24
23:51
When doing a one-pass UPDATE or DELETE on virtual tables, close the cursor prior to running VUpdate. This allows one-pass to work on virtual tables that do not allow concurrent reads and writes. Enhance rtree to take advantage of this new capability. check-in: b816023c user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/rtree/rtree.c.

   129    129     u8 nAux;                    /* # of auxiliary columns in %_rowid */
   130    130     int iDepth;                 /* Current depth of the r-tree structure */
   131    131     char *zDb;                  /* Name of database containing r-tree table */
   132    132     char *zName;                /* Name of r-tree table */ 
   133    133     u32 nBusy;                  /* Current number of users of this structure */
   134    134     i64 nRowEst;                /* Estimated number of rows in this table */
   135    135     u32 nCursor;                /* Number of open cursors */
          136  +  u32 nNodeRef;               /* Number RtreeNodes with positive nRef */
   136    137     char *zReadAuxSql;          /* SQL for statement to read aux data */
   137    138   
   138    139     /* List of nodes removed during a CondenseTree operation. List is
   139    140     ** linked together via the pointer normally used for hash chains -
   140    141     ** RtreeNode.pNext. RtreeNode.iNode stores the depth of the sub-tree 
   141    142     ** headed by the node (leaf nodes have RtreeNode.iNode==0).
   142    143     */
................................................................................
   530    531   }
   531    532   
   532    533   /*
   533    534   ** Increment the reference count of node p.
   534    535   */
   535    536   static void nodeReference(RtreeNode *p){
   536    537     if( p ){
          538  +    assert( p->nRef>0 );
   537    539       p->nRef++;
   538    540     }
   539    541   }
   540    542   
   541    543   /*
   542    544   ** Clear the content of node p (set all bytes to 0x00).
   543    545   */
................................................................................
   597    599   static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){
   598    600     RtreeNode *pNode;
   599    601     pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode) + pRtree->iNodeSize);
   600    602     if( pNode ){
   601    603       memset(pNode, 0, sizeof(RtreeNode) + pRtree->iNodeSize);
   602    604       pNode->zData = (u8 *)&pNode[1];
   603    605       pNode->nRef = 1;
          606  +    pRtree->nNodeRef++;
   604    607       pNode->pParent = pParent;
   605    608       pNode->isDirty = 1;
   606    609       nodeReference(pParent);
   607    610     }
   608    611     return pNode;
   609    612   }
   610    613   
................................................................................
   630    633   ){
   631    634     int rc = SQLITE_OK;
   632    635     RtreeNode *pNode = 0;
   633    636   
   634    637     /* Check if the requested node is already in the hash table. If so,
   635    638     ** increase its reference count and return it.
   636    639     */
   637         -  if( (pNode = nodeHashLookup(pRtree, iNode)) ){
          640  +  if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){
   638    641       assert( !pParent || !pNode->pParent || pNode->pParent==pParent );
   639    642       if( pParent && !pNode->pParent ){
   640         -      nodeReference(pParent);
          643  +      pParent->nRef++;
   641    644         pNode->pParent = pParent;
   642    645       }
   643    646       pNode->nRef++;
   644    647       *ppNode = pNode;
   645    648       return SQLITE_OK;
   646    649     }
   647    650   
................................................................................
   672    675       pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode)+pRtree->iNodeSize);
   673    676       if( !pNode ){
   674    677         rc = SQLITE_NOMEM;
   675    678       }else{
   676    679         pNode->pParent = pParent;
   677    680         pNode->zData = (u8 *)&pNode[1];
   678    681         pNode->nRef = 1;
          682  +      pRtree->nNodeRef++;
   679    683         pNode->iNode = iNode;
   680    684         pNode->isDirty = 0;
   681    685         pNode->pNext = 0;
   682    686         rc = sqlite3_blob_read(pRtree->pNodeBlob, pNode->zData,
   683    687                                pRtree->iNodeSize, 0);
   684    688         nodeReference(pParent);
   685    689       }
................................................................................
   712    716       if( pNode!=0 ){
   713    717         nodeHashInsert(pRtree, pNode);
   714    718       }else{
   715    719         rc = SQLITE_CORRUPT_VTAB;
   716    720       }
   717    721       *ppNode = pNode;
   718    722     }else{
   719         -    sqlite3_free(pNode);
          723  +    if( pNode ){
          724  +      pRtree->nNodeRef--;
          725  +      sqlite3_free(pNode);
          726  +    }
   720    727       *ppNode = 0;
   721    728     }
   722    729   
   723    730     return rc;
   724    731   }
   725    732   
   726    733   /*
................................................................................
   809    816   ** Release a reference to a node. If the node is dirty and the reference
   810    817   ** count drops to zero, the node data is written to the database.
   811    818   */
   812    819   static int nodeRelease(Rtree *pRtree, RtreeNode *pNode){
   813    820     int rc = SQLITE_OK;
   814    821     if( pNode ){
   815    822       assert( pNode->nRef>0 );
          823  +    assert( pRtree->nNodeRef>0 );
   816    824       pNode->nRef--;
   817    825       if( pNode->nRef==0 ){
          826  +      pRtree->nNodeRef--;
   818    827         if( pNode->iNode==1 ){
   819    828           pRtree->iDepth = -1;
   820    829         }
   821    830         if( pNode->pParent ){
   822    831           rc = nodeRelease(pRtree, pNode->pParent);
   823    832         }
   824    833         if( rc==SQLITE_OK ){
................................................................................
   927    936   ** Decrement the r-tree reference count. When the reference count reaches
   928    937   ** zero the structure is deleted.
   929    938   */
   930    939   static void rtreeRelease(Rtree *pRtree){
   931    940     pRtree->nBusy--;
   932    941     if( pRtree->nBusy==0 ){
   933    942       pRtree->inWrTrans = 0;
   934         -    pRtree->nCursor = 0;
          943  +    assert( pRtree->nCursor==0 );
   935    944       nodeBlobReset(pRtree);
          945  +    assert( pRtree->nNodeRef==0 );
   936    946       sqlite3_finalize(pRtree->pWriteNode);
   937    947       sqlite3_finalize(pRtree->pDeleteNode);
   938    948       sqlite3_finalize(pRtree->pReadRowid);
   939    949       sqlite3_finalize(pRtree->pWriteRowid);
   940    950       sqlite3_finalize(pRtree->pDeleteRowid);
   941    951       sqlite3_finalize(pRtree->pReadParent);
   942    952       sqlite3_finalize(pRtree->pWriteParent);
................................................................................
  1399   1409         int ii;
  1400   1410         pNew = rtreeEnqueue(pCur, rScore, iLevel);
  1401   1411         if( pNew==0 ) return 0;
  1402   1412         ii = (int)(pNew - pCur->aPoint) + 1;
  1403   1413         if( ii<RTREE_CACHE_SZ ){
  1404   1414           assert( pCur->aNode[ii]==0 );
  1405   1415           pCur->aNode[ii] = pCur->aNode[0];
  1406         -       }else{
         1416  +      }else{
  1407   1417           nodeRelease(RTREE_OF_CURSOR(pCur), pCur->aNode[0]);
  1408   1418         }
  1409   1419         pCur->aNode[0] = 0;
  1410   1420         *pNew = pCur->sPoint;
  1411   1421       }
  1412   1422       pCur->sPoint.rScore = rScore;
  1413   1423       pCur->sPoint.iLevel = iLevel;
................................................................................
  1890   1900         ** and then a linear search of an R-Tree node. This should be 
  1891   1901         ** considered almost as quick as a direct rowid lookup (for which 
  1892   1902         ** sqlite uses an internal cost of 0.0). It is expected to return
  1893   1903         ** a single row.
  1894   1904         */ 
  1895   1905         pIdxInfo->estimatedCost = 30.0;
  1896   1906         pIdxInfo->estimatedRows = 1;
         1907  +      pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
  1897   1908         return SQLITE_OK;
  1898   1909       }
  1899   1910   
  1900   1911       if( p->usable
  1901   1912       && ((p->iColumn>0 && p->iColumn<=pRtree->nDim2)
  1902   1913           || p->op==SQLITE_INDEX_CONSTRAINT_MATCH)
  1903   1914       ){
................................................................................
  2469   2480       pLeft = nodeNew(pRtree, pNode);
  2470   2481       pRtree->iDepth++;
  2471   2482       pNode->isDirty = 1;
  2472   2483       writeInt16(pNode->zData, pRtree->iDepth);
  2473   2484     }else{
  2474   2485       pLeft = pNode;
  2475   2486       pRight = nodeNew(pRtree, pLeft->pParent);
  2476         -    nodeReference(pLeft);
         2487  +    pLeft->nRef++;
  2477   2488     }
  2478   2489   
  2479   2490     if( !pLeft || !pRight ){
  2480   2491       rc = SQLITE_NOMEM;
  2481   2492       goto splitnode_out;
  2482   2493     }
  2483   2494   
................................................................................
  2959   2970   
  2960   2971     /* Re-insert the contents of any underfull nodes removed from the tree. */
  2961   2972     for(pLeaf=pRtree->pDeleted; pLeaf; pLeaf=pRtree->pDeleted){
  2962   2973       if( rc==SQLITE_OK ){
  2963   2974         rc = reinsertNodeContent(pRtree, pLeaf);
  2964   2975       }
  2965   2976       pRtree->pDeleted = pLeaf->pNext;
         2977  +    pRtree->nNodeRef--;
  2966   2978       sqlite3_free(pLeaf);
  2967   2979     }
  2968   2980   
  2969   2981     /* Release the reference to the root node. */
  2970   2982     if( rc==SQLITE_OK ){
  2971   2983       rc = nodeRelease(pRtree, pRoot);
  2972   2984     }else{
................................................................................
  3063   3075     sqlite_int64 *pRowid
  3064   3076   ){
  3065   3077     Rtree *pRtree = (Rtree *)pVtab;
  3066   3078     int rc = SQLITE_OK;
  3067   3079     RtreeCell cell;                 /* New cell to insert if nData>1 */
  3068   3080     int bHaveRowid = 0;             /* Set to 1 after new rowid is determined */
  3069   3081   
         3082  +  if( pRtree->nNodeRef ){
         3083  +    /* Unable to write to the btree while another cursor is reading from it,
         3084  +    ** since the write might do a rebalance which would disrupt the read
         3085  +    ** cursor. */
         3086  +    return SQLITE_LOCKED_VTAB;
         3087  +  }
  3070   3088     rtreeReference(pRtree);
  3071   3089     assert(nData>=1);
  3072   3090   
  3073   3091     cell.iRowid = 0;  /* Used only to suppress a compiler warning */
  3074   3092   
  3075   3093     /* Constraint handling. A write operation on an r-tree table may return
  3076   3094     ** SQLITE_CONSTRAINT for two reasons:

Changes to ext/rtree/rtree1.test.

   472    472       ABORT    1 1 {1 1 2 3 4   2 2 3 4 5   3 3 4 5 6   4 4 5 6 7}
   473    473       IGNORE   1 0 {1 1 2 3 4   2 2 3 4 5   3 3 4 5 6   4 4 5 6 7  5 8 8 8 8}
   474    474       FAIL     1 1 {1 1 2 3 4   2 2 3 4 5   3 3 4 5 6   4 4 5 6 7  5 8 8 8 8}
   475    475       REPLACE  1 0 {1 1 2 3 4   2 7 7 7 7   3 3 4 5 6   4 4 5 6 7  5 8 8 8 8}
   476    476     }
   477    477   
   478    478     3    "UPDATE %CONF% t1 SET idx = 2 WHERE idx = 4" {
   479         -    ROLLBACK 1 1 {1 1 2 3 4   2 2 3 4 5   3 3 4 5 6}
   480         -    ABORT    1 1 {1 1 2 3 4   2 2 3 4 5   3 3 4 5 6   4 4 5 6 7}
   481         -    IGNORE   1 0 {1 1 2 3 4   2 2 3 4 5   3 3 4 5 6   4 4 5 6 7}
   482         -    FAIL     1 1 {1 1 2 3 4   2 2 3 4 5   3 3 4 5 6   4 4 5 6 7}
   483         -    REPLACE  1 0 {1 1 2 3 4   2 4 5 6 7   3 3 4 5 6}
          479  +    ROLLBACK 0 1 {1 1 2 3 4   2 2 3 4 5   3 3 4 5 6}
          480  +    ABORT    0 1 {1 1 2 3 4   2 2 3 4 5   3 3 4 5 6   4 4 5 6 7}
          481  +    IGNORE   0 0 {1 1 2 3 4   2 2 3 4 5   3 3 4 5 6   4 4 5 6 7}
          482  +    FAIL     0 1 {1 1 2 3 4   2 2 3 4 5   3 3 4 5 6   4 4 5 6 7}
          483  +    REPLACE  0 0 {1 1 2 3 4   2 4 5 6 7   3 3 4 5 6}
   484    484     }
   485    485   
   486    486     3    "UPDATE %CONF% t1 SET idx = ((idx+1)%5)+1 WHERE idx > 2" {
   487    487       ROLLBACK 1 1 {1 1 2 3 4   2 2 3 4 5   3 3 4 5 6}
   488    488       ABORT    1 1 {1 1 2 3 4   2 2 3 4 5   3 3 4 5 6   4 4 5 6 7}
   489    489       IGNORE   1 0 {1 1 2 3 4   2 2 3 4 5               4 4 5 6 7   5 3 4 5 6}
   490    490       FAIL     1 1 {1 1 2 3 4   2 2 3 4 5               4 4 5 6 7   5 3 4 5 6}

Changes to ext/rtree/rtree8.test.

    34     34   do_test rtree8-1.1.1 {
    35     35     execsql { PRAGMA page_size = 512 }
    36     36     execsql { CREATE VIRTUAL TABLE t1 USING rtree_i32(id, x1, x2) }
    37     37     populate_t1 5
    38     38   } {}
    39     39   do_test rtree8-1.1.2 {
    40     40     set res [list]
    41         -  db eval { SELECT * FROM t1 } { 
    42         -    lappend res $x1 $x2
           41  +  set rc [catch {
           42  +    db eval { SELECT * FROM t1 } { 
           43  +      lappend res $x1 $x2
           44  +      if {$id==3} { db eval { DELETE FROM t1 WHERE id>3 } }
           45  +    }
           46  +  } msg];
           47  +  lappend rc $msg
           48  +  set rc
           49  +} {1 {database table is locked}}
           50  +do_test rtree8-1.1.2b {
           51  +  db eval { SELECT * FROM t1 ORDER BY +id } { 
    43     52       if {$id==3} { db eval { DELETE FROM t1 WHERE id>3 } }
    44     53     }
    45         -  set res
           54  +  db eval {SELECT x1, x2 FROM t1}
    46     55   } {1 3 2 4 3 5}
    47     56   do_test rtree8-1.1.3 {
    48     57     execsql { SELECT * FROM t1 }
    49     58   } {1 1 3 2 2 4 3 3 5}
    50     59   
    51     60   # Many SELECTs on the same small table.
    52     61   #
................................................................................
   165    174     execsql BEGIN
   166    175     for {set i 0} {$i < 200} {incr i} {
   167    176       execsql { DELETE FROM t2 WHERE id = $i }
   168    177     }
   169    178     execsql COMMIT
   170    179   } {}
   171    180   do_rtree_integrity_test rtree8-5.5 t2
          181  +
          182  +# 2018-05-24
          183  +# The following script caused an assertion fault and/or segfault
          184  +# prior to the fix that prevents simultaneous reads and writes on
          185  +# the same rtree virtual table.
          186  +#
          187  +do_test rtree8-6.1 {
          188  +  db close
          189  +  sqlite3 db :memory:
          190  +  db eval {
          191  +    PRAGMA page_size=512;
          192  +    CREATE VIRTUAL TABLE t1 USING rtree(id,x1,x2,y1,y2);
          193  +    WITH RECURSIVE c(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM c WHERE x<49)
          194  +    INSERT INTO t1 SELECT x, x, x+1, x, x+1 FROM c;
          195  +  }
          196  +  set rc [catch {
          197  +    db eval {SELECT id FROM t1} x {
          198  +      db eval {DELETE FROM t1 WHERE id=$x(id)}
          199  +    }
          200  +  } msg]
          201  +  lappend rc $msg
          202  +} {1 {database table is locked}}
          203  +
          204  +
   172    205   
   173    206   
   174    207   finish_test

Changes to src/delete.c.

   549    549       }  
   550    550     
   551    551       /* Delete the row */
   552    552   #ifndef SQLITE_OMIT_VIRTUALTABLE
   553    553       if( IsVirtual(pTab) ){
   554    554         const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
   555    555         sqlite3VtabMakeWritable(pParse, pTab);
   556         -      sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB);
   557         -      sqlite3VdbeChangeP5(v, OE_Abort);
   558    556         assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE );
   559    557         sqlite3MayAbort(pParse);
   560         -      if( eOnePass==ONEPASS_SINGLE && sqlite3IsToplevel(pParse) ){
   561         -        pParse->isMultiWrite = 0;
          558  +      if( eOnePass==ONEPASS_SINGLE ){
          559  +        sqlite3VdbeAddOp1(v, OP_Close, iTabCur);
          560  +        if( sqlite3IsToplevel(pParse) ){
          561  +          pParse->isMultiWrite = 0;
          562  +        }
   562    563         }
          564  +      sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB);
          565  +      sqlite3VdbeChangeP5(v, OE_Abort);
   563    566       }else
   564    567   #endif
   565    568       {
   566    569         int count = (pParse->nested==0);    /* True to count changes */
   567    570         sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
   568    571             iKey, nKey, count, OE_Default, eOnePass, aiCurOnePass[1]);
   569    572       }

Changes to src/insert.c.

   222    222   */
   223    223   static int autoIncBegin(
   224    224     Parse *pParse,      /* Parsing context */
   225    225     int iDb,            /* Index of the database holding pTab */
   226    226     Table *pTab         /* The table we are writing to */
   227    227   ){
   228    228     int memId = 0;      /* Register holding maximum rowid */
          229  +  assert( pParse->db->aDb[iDb].pSchema!=0 );
   229    230     if( (pTab->tabFlags & TF_Autoincrement)!=0
   230    231      && (pParse->db->mDbFlags & DBFLAG_Vacuum)==0
   231    232     ){
   232    233       Parse *pToplevel = sqlite3ParseToplevel(pParse);
   233    234       AutoincInfo *pInfo;
          235  +    Table *pSeqTab = pParse->db->aDb[iDb].pSchema->pSeqTab;
          236  +
          237  +    /* Verify that the sqlite_sequence table exists and is an ordinary
          238  +    ** rowid table with exactly two columns.
          239  +    ** Ticket d8dc2b3a58cd5dc2918a1d4acb 2018-05-23 */
          240  +    if( pSeqTab==0
          241  +     || !HasRowid(pSeqTab)
          242  +     || IsVirtual(pSeqTab)
          243  +     || pSeqTab->nCol!=2
          244  +    ){
          245  +      pParse->nErr++;
          246  +      pParse->rc = SQLITE_CORRUPT_SEQUENCE;
          247  +      return 0;
          248  +    }
   234    249   
   235    250       pInfo = pToplevel->pAinc;
   236    251       while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; }
   237    252       if( pInfo==0 ){
   238    253         pInfo = sqlite3DbMallocRawNN(pParse->db, sizeof(*pInfo));
   239    254         if( pInfo==0 ) return 0;
   240    255         pInfo->pNext = pToplevel->pAinc;

Changes to src/sqlite.h.in.

   500    500   #define SQLITE_IOERR_CONVPATH          (SQLITE_IOERR | (26<<8))
   501    501   #define SQLITE_IOERR_VNODE             (SQLITE_IOERR | (27<<8))
   502    502   #define SQLITE_IOERR_AUTH              (SQLITE_IOERR | (28<<8))
   503    503   #define SQLITE_IOERR_BEGIN_ATOMIC      (SQLITE_IOERR | (29<<8))
   504    504   #define SQLITE_IOERR_COMMIT_ATOMIC     (SQLITE_IOERR | (30<<8))
   505    505   #define SQLITE_IOERR_ROLLBACK_ATOMIC   (SQLITE_IOERR | (31<<8))
   506    506   #define SQLITE_LOCKED_SHAREDCACHE      (SQLITE_LOCKED |  (1<<8))
          507  +#define SQLITE_LOCKED_VTAB             (SQLITE_LOCKED |  (2<<8))
   507    508   #define SQLITE_BUSY_RECOVERY           (SQLITE_BUSY   |  (1<<8))
   508    509   #define SQLITE_BUSY_SNAPSHOT           (SQLITE_BUSY   |  (2<<8))
   509    510   #define SQLITE_CANTOPEN_NOTEMPDIR      (SQLITE_CANTOPEN | (1<<8))
   510    511   #define SQLITE_CANTOPEN_ISDIR          (SQLITE_CANTOPEN | (2<<8))
   511    512   #define SQLITE_CANTOPEN_FULLPATH       (SQLITE_CANTOPEN | (3<<8))
   512    513   #define SQLITE_CANTOPEN_CONVPATH       (SQLITE_CANTOPEN | (4<<8))
   513    514   #define SQLITE_CORRUPT_VTAB            (SQLITE_CORRUPT | (1<<8))
          515  +#define SQLITE_CORRUPT_SEQUENCE        (SQLITE_CORRUPT | (2<<8))
   514    516   #define SQLITE_READONLY_RECOVERY       (SQLITE_READONLY | (1<<8))
   515    517   #define SQLITE_READONLY_CANTLOCK       (SQLITE_READONLY | (2<<8))
   516    518   #define SQLITE_READONLY_ROLLBACK       (SQLITE_READONLY | (3<<8))
   517    519   #define SQLITE_READONLY_DBMOVED        (SQLITE_READONLY | (4<<8))
   518    520   #define SQLITE_READONLY_CANTINIT       (SQLITE_READONLY | (5<<8))
   519    521   #define SQLITE_READONLY_DIRECTORY      (SQLITE_READONLY | (6<<8))
   520    522   #define SQLITE_ABORT_ROLLBACK          (SQLITE_ABORT | (2<<8))
................................................................................
  8529   8531   /*
  8530   8532   ** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE
  8531   8533   **
  8532   8534   ** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn]
  8533   8535   ** method of a [virtual table], then it returns true if and only if the
  8534   8536   ** column is being fetched as part of an UPDATE operation during which the
  8535   8537   ** column value will not change.  Applications might use this to substitute
  8536         -** a lighter-weight value to return that the corresponding [xUpdate] method
  8537         -** understands as a "no-change" value.
         8538  +** a return value that is less expensive to compute and that the corresponding
         8539  +** [xUpdate] method understands as a "no-change" value.
  8538   8540   **
  8539   8541   ** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that
  8540         -** the column is not changed by the UPDATE statement, they the xColumn
         8542  +** the column is not changed by the UPDATE statement, then the xColumn
  8541   8543   ** method can optionally return without setting a result, without calling
  8542   8544   ** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces].
  8543   8545   ** In that case, [sqlite3_value_nochange(X)] will return true for the
  8544   8546   ** same column in the [xUpdate] method.
  8545   8547   */
  8546   8548   int sqlite3_vtab_nochange(sqlite3_context*);
  8547   8549   

Changes to src/test_malloc.c.

    28     28   ** by malloc() fault simulation.
    29     29   */
    30     30   static struct MemFault {
    31     31     int iCountdown;         /* Number of pending successes before a failure */
    32     32     int nRepeat;            /* Number of times to repeat the failure */
    33     33     int nBenign;            /* Number of benign failures seen since last config */
    34     34     int nFail;              /* Number of failures seen since last config */
           35  +  int nOkBefore;          /* Successful allocations prior to the first fault */
           36  +  int nOkAfter;           /* Successful allocations after a fault */
    35     37     u8 enable;              /* True if enabled */
    36     38     int isInstalled;        /* True if the fault simulation layer is installed */
    37     39     int isBenignMode;       /* True if malloc failures are considered benign */
    38     40     sqlite3_mem_methods m;  /* 'Real' malloc implementation */
    39     41   } memfault;
    40     42   
    41     43   /*
................................................................................
    42     44   ** This routine exists as a place to set a breakpoint that will
    43     45   ** fire on any simulated malloc() failure.
    44     46   */
    45     47   static void sqlite3Fault(void){
    46     48     static int cnt = 0;
    47     49     cnt++;
    48     50   }
           51  +
           52  +/*
           53  +** This routine exists as a place to set a breakpoint that will
           54  +** fire the first time any malloc() fails on a single test case.
           55  +** The sqlite3Fault() routine above runs on every malloc() failure.
           56  +** This routine only runs on the first such failure.
           57  +*/
           58  +static void sqlite3FirstFault(void){
           59  +  static int cnt2 = 0;
           60  +  cnt2++;
           61  +}
    49     62   
    50     63   /*
    51     64   ** Check to see if a fault should be simulated.  Return true to simulate
    52     65   ** the fault.  Return false if the fault should not be simulated.
    53     66   */
    54     67   static int faultsimStep(void){
    55     68     if( likely(!memfault.enable) ){
           69  +    memfault.nOkAfter++;
    56     70       return 0;
    57     71     }
    58     72     if( memfault.iCountdown>0 ){
    59     73       memfault.iCountdown--;
           74  +    memfault.nOkBefore++;
    60     75       return 0;
    61     76     }
           77  +  if( memfault.nFail==0 ) sqlite3FirstFault();
    62     78     sqlite3Fault();
    63     79     memfault.nFail++;
    64     80     if( memfault.isBenignMode>0 ){
    65     81       memfault.nBenign++;
    66     82     }
    67     83     memfault.nRepeat--;
    68     84     if( memfault.nRepeat<=0 ){
................................................................................
   129    145   ** to succeed again.
   130    146   */
   131    147   static void faultsimConfig(int nDelay, int nRepeat){
   132    148     memfault.iCountdown = nDelay;
   133    149     memfault.nRepeat = nRepeat;
   134    150     memfault.nBenign = 0;
   135    151     memfault.nFail = 0;
          152  +  memfault.nOkBefore = 0;
          153  +  memfault.nOkAfter = 0;
   136    154     memfault.enable = nDelay>=0;
   137    155   
   138    156     /* Sometimes, when running multi-threaded tests, the isBenignMode 
   139    157     ** variable is not properly incremented/decremented so that it is
   140    158     ** 0 when not inside a benign malloc block. This doesn't affect
   141    159     ** the multi-threaded tests, as they do not use this system. But
   142    160     ** it does affect OOM tests run later in the same process. So

Changes to src/update.c.

   841    841     WhereInfo *pWInfo;
   842    842     int nArg = 2 + pTab->nCol;      /* Number of arguments to VUpdate */
   843    843     int regArg;                     /* First register in VUpdate arg array */
   844    844     int regRec;                     /* Register in which to assemble record */
   845    845     int regRowid;                   /* Register for ephem table rowid */
   846    846     int iCsr = pSrc->a[0].iCursor;  /* Cursor used for virtual table scan */
   847    847     int aDummy[2];                  /* Unused arg for sqlite3WhereOkOnePass() */
   848         -  int bOnePass;                   /* True to use onepass strategy */
          848  +  int eOnePass;                   /* True to use onepass strategy */
   849    849     int addr;                       /* Address of OP_OpenEphemeral */
   850    850   
   851    851     /* Allocate nArg registers in which to gather the arguments for VUpdate. Then
   852    852     ** create and open the ephemeral table in which the records created from
   853    853     ** these arguments will be temporarily stored. */
   854    854     assert( v );
   855    855     ephemTab = pParse->nTab++;
................................................................................
   886    886       assert( pPk!=0 );
   887    887       assert( pPk->nKeyCol==1 );
   888    888       iPk = pPk->aiColumn[0];
   889    889       sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, iPk, regArg);
   890    890       sqlite3VdbeAddOp2(v, OP_SCopy, regArg+2+iPk, regArg+1);
   891    891     }
   892    892   
   893         -  bOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);
          893  +  eOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);
          894  +
          895  +  /* There is no ONEPASS_MULTI on virtual tables */
          896  +  assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE );
   894    897   
   895         -  if( bOnePass ){
          898  +  if( eOnePass ){
   896    899       /* If using the onepass strategy, no-op out the OP_OpenEphemeral coded
   897    900       ** above. */
   898    901       sqlite3VdbeChangeToNoop(v, addr);
          902  +    sqlite3VdbeAddOp1(v, OP_Close, iCsr);
   899    903     }else{
   900    904       /* Create a record from the argument register contents and insert it into
   901    905       ** the ephemeral table. */
   902    906       sqlite3MultiWrite(pParse);
   903    907       sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec);
   904    908   #ifdef SQLITE_DEBUG
   905    909       /* Signal an assert() within OP_MakeRecord that it is allowed to
................................................................................
   907    911       sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC);
   908    912   #endif
   909    913       sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid);
   910    914       sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid);
   911    915     }
   912    916   
   913    917   
   914         -  if( bOnePass==0 ){
          918  +  if( eOnePass==ONEPASS_OFF ){
   915    919       /* End the virtual table scan */
   916    920       sqlite3WhereEnd(pWInfo);
   917    921   
   918    922       /* Begin scannning through the ephemeral table. */
   919    923       addr = sqlite3VdbeAddOp1(v, OP_Rewind, ephemTab); VdbeCoverage(v);
   920    924   
   921    925       /* Extract arguments from the current row of the ephemeral table and 
................................................................................
   927    931     sqlite3VtabMakeWritable(pParse, pTab);
   928    932     sqlite3VdbeAddOp4(v, OP_VUpdate, 0, nArg, regArg, pVTab, P4_VTAB);
   929    933     sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError);
   930    934     sqlite3MayAbort(pParse);
   931    935   
   932    936     /* End of the ephemeral table scan. Or, if using the onepass strategy,
   933    937     ** jump to here if the scan visited zero rows. */
   934         -  if( bOnePass==0 ){
          938  +  if( eOnePass==ONEPASS_OFF ){
   935    939       sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1); VdbeCoverage(v);
   936    940       sqlite3VdbeJumpHere(v, addr);
   937    941       sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);
   938    942     }else{
   939    943       sqlite3WhereEnd(pWInfo);
   940    944     }
   941    945   }
   942    946   #endif /* SQLITE_OMIT_VIRTUALTABLE */

Changes to src/vdbe.c.

  4283   4283     VdbeFrame *pFrame;     /* Root frame of VDBE */
  4284   4284   
  4285   4285     v = 0;
  4286   4286     res = 0;
  4287   4287     pOut = out2Prerelease(p, pOp);
  4288   4288     assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  4289   4289     pC = p->apCsr[pOp->p1];
  4290         -  if( !pC->isTable ){
  4291         -    rc = SQLITE_CORRUPT_BKPT;
  4292         -    goto abort_due_to_error;
  4293         -  }
  4294   4290     assert( pC!=0 );
         4291  +  assert( pC->isTable );
  4295   4292     assert( pC->eCurType==CURTYPE_BTREE );
  4296   4293     assert( pC->uc.pCursor!=0 );
  4297   4294     {
  4298   4295       /* The next rowid or record number (different terms for the same
  4299   4296       ** thing) is obtained in a two-step algorithm.
  4300   4297       **
  4301   4298       ** First we attempt to find the largest existing rowid and add one
................................................................................
  6747   6744   **
  6748   6745   ** Store in register P3 the value of the P2-th column of
  6749   6746   ** the current row of the virtual-table of cursor P1.
  6750   6747   **
  6751   6748   ** If the VColumn opcode is being used to fetch the value of
  6752   6749   ** an unchanging column during an UPDATE operation, then the P5
  6753   6750   ** value is 1.  Otherwise, P5 is 0.  The P5 value is returned
  6754         -** by sqlite3_vtab_nochange() routine can can be used
         6751  +** by sqlite3_vtab_nochange() routine and can be used
  6755   6752   ** by virtual table implementations to return special "no-change"
  6756   6753   ** marks which can be more efficient, depending on the virtual table.
  6757   6754   */
  6758   6755   case OP_VColumn: {
  6759   6756     sqlite3_vtab *pVtab;
  6760   6757     const sqlite3_module *pModule;
  6761   6758     Mem *pDest;

Changes to test/autoinc.test.

   679    679   #
   680    680   do_execsql_test autoinc-11.1 {
   681    681     CREATE TABLE t11(a INTEGER PRIMARY KEY AUTOINCREMENT,b UNIQUE);
   682    682     INSERT INTO t11(a,b) VALUES(2,3),(5,6),(4,3),(1,2)
   683    683       ON CONFLICT(b) DO UPDATE SET a=a+1000;
   684    684     SELECT seq FROM sqlite_sequence WHERE name='t11';
   685    685   } {5}
          686  +
          687  +# 2018-05-23 ticket d8dc2b3a58cd5dc2918a1d4acbba4676a23ada4c
          688  +# Does not crash if the sqlite_sequence table schema is missing
          689  +# or corrupt.
          690  +#
          691  +do_test autoinc-12.1 {
          692  +  db close
          693  +  forcedelete test.db
          694  +  sqlite3 db test.db
          695  +  db eval {
          696  +    CREATE TABLE fake_sequence(name TEXT PRIMARY KEY,seq) WITHOUT ROWID;
          697  +    PRAGMA writable_schema=on;
          698  +    UPDATE sqlite_master SET
          699  +     sql=replace(sql,'fake_','sqlite_'),
          700  +     name='sqlite_sequence',
          701  +     tbl_name='sqlite_sequence'
          702  +     WHERE name='fake_sequence';
          703  +  }
          704  +  db close
          705  +  sqlite3 db test.db
          706  +  set res [catch {db eval {
          707  +    CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);
          708  +    INSERT INTO t1(b) VALUES('one');
          709  +  }} msg]
          710  +  lappend res $msg
          711  +} {1 {database disk image is malformed}}
          712  +do_test autoinc-12.2 {
          713  +  db close
          714  +  forcedelete test.db
          715  +  sqlite3 db test.db
          716  +  db eval {
          717  +   CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);
          718  +   INSERT INTO t1(b) VALUES('one');
          719  +   PRAGMA writable_schema=on;
          720  +   UPDATE sqlite_master SET
          721  +     sql=replace(sql,'sqlite_','x_'),
          722  +     name='x_sequence',
          723  +     tbl_name='x_sequence'
          724  +    WHERE name='sqlite_sequence';
          725  +  }
          726  +  db close
          727  +  sqlite3 db test.db
          728  +  set res [catch {db eval {
          729  +    INSERT INTO t1(b) VALUES('two');
          730  +  }} msg]
          731  +  lappend res $msg
          732  +} {1 {database disk image is malformed}}
          733  +do_test autoinc-12.3 {
          734  +  db close
          735  +  forcedelete test.db
          736  +  sqlite3 db test.db
          737  +  db eval {
          738  +   CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);
          739  +   INSERT INTO t1(b) VALUES('one');
          740  +   PRAGMA writable_schema=on;
          741  +   UPDATE sqlite_master SET
          742  +     sql='CREATE VIRTUAL TABLE sqlite_sequence USING sqlite_dbpage'
          743  +    WHERE name='sqlite_sequence';
          744  +  }
          745  +  db close
          746  +  sqlite3 db test.db
          747  +  set res [catch {db eval {
          748  +    INSERT INTO t1(b) VALUES('two');
          749  +  }} msg]
          750  +  lappend res $msg
          751  +} {1 {database disk image is malformed}}
          752  +do_test autoinc-12.4 {
          753  +  db close
          754  +  forcedelete test.db
          755  +  sqlite3 db test.db
          756  +  db eval {
          757  +    CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);
          758  +    INSERT INTO t1(b) VALUES('one');
          759  +    CREATE TABLE fake(name TEXT PRIMARY KEY,seq) WITHOUT ROWID;
          760  +  }
          761  +  set root1 [db one {SELECT rootpage FROM sqlite_master
          762  +                     WHERE name='sqlite_sequence'}]
          763  +  set root2 [db one {SELECT rootpage FROM sqlite_master
          764  +                     WHERE name='fake'}]
          765  +  db eval {
          766  +   PRAGMA writable_schema=on;
          767  +   UPDATE sqlite_master SET rootpage=$root2
          768  +    WHERE name='sqlite_sequence';
          769  +   UPDATE sqlite_master SET rootpage=$root1
          770  +    WHERE name='fake';
          771  +  }
          772  +  db close
          773  +  sqlite3 db test.db
          774  +  set res [catch {db eval {
          775  +    INSERT INTO t1(b) VALUES('two');
          776  +  }} msg]
          777  +  lappend res $msg
          778  +} {1 {database disk image is malformed}}
          779  +breakpoint
          780  +do_test autoinc-12.5 {
          781  +  db close
          782  +  forcedelete test.db
          783  +  sqlite3 db test.db
          784  +  db eval {
          785  +    CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);
          786  +    INSERT INTO t1(b) VALUES('one');
          787  +    PRAGMA writable_schema=on;
          788  +    UPDATE sqlite_master SET
          789  +       sql='CREATE TABLE sqlite_sequence(x)'
          790  +      WHERE name='sqlite_sequence';
          791  +  }
          792  +  db close
          793  +  sqlite3 db test.db
          794  +  set res [catch {db eval {
          795  +    INSERT INTO t1(b) VALUES('two');
          796  +  }} msg]
          797  +  lappend res $msg
          798  +} {1 {database disk image is malformed}}
          799  +do_test autoinc-12.6 {
          800  +  db close
          801  +  forcedelete test.db
          802  +  sqlite3 db test.db
          803  +  db eval {
          804  +    CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);
          805  +    INSERT INTO t1(b) VALUES('one');
          806  +    PRAGMA writable_schema=on;
          807  +    UPDATE sqlite_master SET
          808  +       sql='CREATE TABLE sqlite_sequence(x,y INTEGER PRIMARY KEY)'
          809  +      WHERE name='sqlite_sequence';
          810  +  }
          811  +  db close
          812  +  sqlite3 db test.db
          813  +  set res [catch {db eval {
          814  +    INSERT INTO t1(b) VALUES('two'),('three'),('four');
          815  +    INSERT INTO t1(b) VALUES('five');
          816  +    PRAGMA integrity_check;
          817  +  }} msg]
          818  +  lappend res $msg
          819  +} {0 ok}
          820  +do_test autoinc-12.7 {
          821  +  db close
          822  +  forcedelete test.db
          823  +  sqlite3 db test.db
          824  +  db eval {
          825  +    CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);
          826  +    INSERT INTO t1(b) VALUES('one');
          827  +    PRAGMA writable_schema=on;
          828  +    UPDATE sqlite_master SET
          829  +       sql='CREATE TABLE sqlite_sequence(y INTEGER PRIMARY KEY,x)'
          830  +      WHERE name='sqlite_sequence';
          831  +  }
          832  +  db close
          833  +  sqlite3 db test.db
          834  +  set res [catch {db eval {
          835  +    INSERT INTO t1(b) VALUES('two'),('three'),('four');
          836  +    INSERT INTO t1(b) VALUES('five');
          837  +    PRAGMA integrity_check;
          838  +  }} msg]
          839  +  lappend res $msg
          840  +} {0 ok}
   686    841   
   687    842   finish_test

Changes to test/speedtest1.c.

  1243   1243   ** A testset for the R-Tree virtual table
  1244   1244   */
  1245   1245   void testset_rtree(int p1, int p2){
  1246   1246     unsigned i, n;
  1247   1247     unsigned mxCoord;
  1248   1248     unsigned x0, x1, y0, y1, z0, z1;
  1249   1249     unsigned iStep;
         1250  +  unsigned mxRowid;
  1250   1251     int *aCheck = sqlite3_malloc( sizeof(int)*g.szTest*500 );
  1251   1252   
  1252   1253     mxCoord = 15000;
  1253         -  n = g.szTest*500;
         1254  +  mxRowid = n = g.szTest*500;
  1254   1255     speedtest1_begin_test(100, "%d INSERTs into an r-tree", n);
  1255   1256     speedtest1_exec("BEGIN");
  1256   1257     speedtest1_exec("CREATE VIRTUAL TABLE rt1 USING rtree(id,x0,x1,y0,y1,z0,z1)");
  1257   1258     speedtest1_prepare("INSERT INTO rt1(id,x0,x1,y0,y1,z0,z1)"
  1258   1259                        "VALUES(?1,?2,?3,?4,?5,?6,?7)");
  1259   1260     for(i=1; i<=n; i++){
  1260   1261       twoCoords(p1, p2, mxCoord, &x0, &x1);
................................................................................
  1273   1274     speedtest1_end_test();
  1274   1275   
  1275   1276     speedtest1_begin_test(101, "Copy from rtree to a regular table");
  1276   1277     speedtest1_exec("CREATE TABLE t1(id INTEGER PRIMARY KEY,x0,x1,y0,y1,z0,z1)");
  1277   1278     speedtest1_exec("INSERT INTO t1 SELECT * FROM rt1");
  1278   1279     speedtest1_end_test();
  1279   1280   
  1280         -  n = g.szTest*100;
         1281  +  n = g.szTest*200;
  1281   1282     speedtest1_begin_test(110, "%d one-dimensional intersect slice queries", n);
  1282   1283     speedtest1_prepare("SELECT count(*) FROM rt1 WHERE x0>=?1 AND x1<=?2");
  1283   1284     iStep = mxCoord/n;
  1284   1285     for(i=0; i<n; i++){
  1285   1286       sqlite3_bind_int(g.pStmt, 1, i*iStep);
  1286   1287       sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
  1287   1288       speedtest1_run();
  1288   1289       aCheck[i] = atoi(g.zResult);
  1289   1290     }
  1290   1291     speedtest1_end_test();
  1291   1292   
  1292   1293     if( g.bVerify ){
  1293         -    n = g.szTest*100;
         1294  +    n = g.szTest*200;
  1294   1295       speedtest1_begin_test(111, "Verify result from 1-D intersect slice queries");
  1295   1296       speedtest1_prepare("SELECT count(*) FROM t1 WHERE x0>=?1 AND x1<=?2");
  1296   1297       iStep = mxCoord/n;
  1297   1298       for(i=0; i<n; i++){
  1298   1299         sqlite3_bind_int(g.pStmt, 1, i*iStep);
  1299   1300         sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
  1300   1301         speedtest1_run();
................................................................................
  1302   1303           fatal_error("Count disagree step %d: %d..%d.  %d vs %d",
  1303   1304                       i, i*iStep, (i+1)*iStep, aCheck[i], atoi(g.zResult));
  1304   1305         }
  1305   1306       }
  1306   1307       speedtest1_end_test();
  1307   1308     }
  1308   1309     
  1309         -  n = g.szTest*100;
         1310  +  n = g.szTest*200;
  1310   1311     speedtest1_begin_test(120, "%d one-dimensional overlap slice queries", n);
  1311   1312     speedtest1_prepare("SELECT count(*) FROM rt1 WHERE y1>=?1 AND y0<=?2");
  1312   1313     iStep = mxCoord/n;
  1313   1314     for(i=0; i<n; i++){
  1314   1315       sqlite3_bind_int(g.pStmt, 1, i*iStep);
  1315   1316       sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
  1316   1317       speedtest1_run();
  1317   1318       aCheck[i] = atoi(g.zResult);
  1318   1319     }
  1319   1320     speedtest1_end_test();
  1320   1321   
  1321   1322     if( g.bVerify ){
  1322         -    n = g.szTest*100;
         1323  +    n = g.szTest*200;
  1323   1324       speedtest1_begin_test(121, "Verify result from 1-D overlap slice queries");
  1324   1325       speedtest1_prepare("SELECT count(*) FROM t1 WHERE y1>=?1 AND y0<=?2");
  1325   1326       iStep = mxCoord/n;
  1326   1327       for(i=0; i<n; i++){
  1327   1328         sqlite3_bind_int(g.pStmt, 1, i*iStep);
  1328   1329         sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
  1329   1330         speedtest1_run();
................................................................................
  1332   1333                       i, i*iStep, (i+1)*iStep, aCheck[i], atoi(g.zResult));
  1333   1334         }
  1334   1335       }
  1335   1336       speedtest1_end_test();
  1336   1337     }
  1337   1338     
  1338   1339   
  1339         -  n = g.szTest*100;
         1340  +  n = g.szTest*200;
  1340   1341     speedtest1_begin_test(125, "%d custom geometry callback queries", n);
  1341   1342     sqlite3_rtree_geometry_callback(g.db, "xslice", xsliceGeometryCallback, 0);
  1342   1343     speedtest1_prepare("SELECT count(*) FROM rt1 WHERE id MATCH xslice(?1,?2)");
  1343   1344     iStep = mxCoord/n;
  1344   1345     for(i=0; i<n; i++){
  1345   1346       sqlite3_bind_int(g.pStmt, 1, i*iStep);
  1346   1347       sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
................................................................................
  1369   1370     speedtest1_begin_test(140, "%d rowid queries", n);
  1370   1371     speedtest1_prepare("SELECT * FROM rt1 WHERE id=?1");
  1371   1372     for(i=1; i<=n; i++){
  1372   1373       sqlite3_bind_int(g.pStmt, 1, i);
  1373   1374       speedtest1_run();
  1374   1375     }
  1375   1376     speedtest1_end_test();
         1377  +
         1378  +  n = g.szTest*50;
         1379  +  speedtest1_begin_test(150, "%d UPDATEs using rowid", n);
         1380  +  speedtest1_prepare("UPDATE rt1 SET x0=x0+100, x1=x1+100 WHERE id=?1");
         1381  +  for(i=1; i<=n; i++){
         1382  +    sqlite3_bind_int(g.pStmt, 1, (i*251)%mxRowid + 1);
         1383  +    speedtest1_run();
         1384  +  }
         1385  +  speedtest1_end_test();
         1386  +
         1387  +  n = g.szTest*5;
         1388  +  speedtest1_begin_test(155, "%d UPDATEs using one-dimensional overlap", n);
         1389  +  speedtest1_prepare("UPDATE rt1 SET x0=x0-100, x1=x1-100"
         1390  +                     " WHERE y1>=?1 AND y0<=?1+5");
         1391  +  iStep = mxCoord/n;
         1392  +  for(i=0; i<n; i++){
         1393  +    sqlite3_bind_int(g.pStmt, 1, i*iStep);
         1394  +    speedtest1_run();
         1395  +    aCheck[i] = atoi(g.zResult);
         1396  +  }
         1397  +  speedtest1_end_test();
         1398  +
         1399  +  n = g.szTest*50;
         1400  +  speedtest1_begin_test(160, "%d DELETEs using rowid", n);
         1401  +  speedtest1_prepare("DELETE FROM rt1 WHERE id=?1");
         1402  +  for(i=1; i<=n; i++){
         1403  +    sqlite3_bind_int(g.pStmt, 1, (i*257)%mxRowid + 1);
         1404  +    speedtest1_run();
         1405  +  }
         1406  +  speedtest1_end_test();
         1407  +
         1408  +
         1409  +  n = g.szTest*5;
         1410  +  speedtest1_begin_test(165, "%d DELETEs using one-dimensional overlap", n);
         1411  +  speedtest1_prepare("DELETE FROM rt1 WHERE y1>=?1 AND y0<=?1+5");
         1412  +  iStep = mxCoord/n;
         1413  +  for(i=0; i<n; i++){
         1414  +    sqlite3_bind_int(g.pStmt, 1, i*iStep);
         1415  +    speedtest1_run();
         1416  +    aCheck[i] = atoi(g.zResult);
         1417  +  }
         1418  +  speedtest1_end_test();
         1419  +
         1420  +  speedtest1_begin_test(170, "Restore deleted entries using INSERT OR IGNORE");
         1421  +  speedtest1_exec("INSERT OR IGNORE INTO rt1 SELECT * FROM t1");
         1422  +  speedtest1_end_test();
  1376   1423   }
  1377   1424   #endif /* SQLITE_ENABLE_RTREE */
  1378   1425   
  1379   1426   /*
  1380   1427   ** A testset that does key/value storage on tables with many columns.
  1381   1428   ** This is the kind of workload generated by ORMs such as CoreData.
  1382   1429   */

Changes to tool/speed-check.sh.

    37     37   LEAN_OPTS="$LEAN_OPTS -DSQLITE_OMIT_SHARED_CACHE"
    38     38   LEAN_OPTS="$LEAN_OPTS -DSQLITE_USE_ALLOCA"
    39     39   BASELINE="trunk"
    40     40   doExplain=0
    41     41   doCachegrind=1
    42     42   doVdbeProfile=0
    43     43   doWal=1
           44  +doDiff=1
    44     45   while test "$1" != ""; do
    45     46     case $1 in
           47  +    --nodiff)
           48  +	doDiff=0
           49  +        ;;
    46     50       --reprepare)
    47     51           SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1"
    48     52           ;;
    49     53       --autovacuum)
    50     54           SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1"
    51     55           ;;
    52     56       --utf16be)
................................................................................
   175    179   if test $doExplain -eq 1; then
   176    180     ./speedtest1 --explain $SPEEDTEST_OPTS | ./sqlite3 >explain-$NAME.txt
   177    181   fi
   178    182   if test $doVdbeProfile -eq 1; then
   179    183     tclsh ../sqlite/tool/vdbe_profile.tcl >vdbeprofile-$NAME.txt
   180    184     open vdbeprofile-$NAME.txt
   181    185   fi
   182         -if test "$NAME" != "$BASELINE" -a $doVdbeProfile -ne 1; then
          186  +if test "$NAME" != "$BASELINE" -a $doVdbeProfile -ne 1 -a $doDiff -ne 0; then
   183    187     fossil test-diff --tk -c 20 cout-$BASELINE.txt cout-$NAME.txt
   184    188   fi