/ Check-in [322a5f08]
Login

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

Overview
Comment:Candidate fix for ticket [6bfb98dfc0c]: Make sure invalid cursors drop all references to database pages prior to doing any insert or update.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 322a5f086d9ee46017f750df81527799a54ae258
User & Date: drh 2013-03-27 03:15:23
Context
2013-03-27
17:20
In order to optimize out the ORDER BY clause, outer loops must generate values for ORDER BY terms that are unique or else the inner loops must generate no more than a single row. Fix for ticket [a179fe7465]. check-in: 2936f746 user: drh tags: trunk
15:04
A fix and test-case for the ORDER BY problem identified by ticket [a179fe7465]. This change causes sorting to occur in some cases where it is not strictly necessary. Further work is needed to avoid those extra sorts. check-in: 488089e6 user: drh tags: orderby-fix
03:15
Candidate fix for ticket [6bfb98dfc0c]: Make sure invalid cursors drop all references to database pages prior to doing any insert or update. check-in: 322a5f08 user: drh tags: trunk
2013-03-25
12:02
Add a second test for [38b1ae018f]. check-in: 5062db67 user: dan tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btree.c.

   570    570   ** Clear (destroy) the BtShared.pHasContent bitvec. This should be
   571    571   ** invoked at the conclusion of each write-transaction.
   572    572   */
   573    573   static void btreeClearHasContent(BtShared *pBt){
   574    574     sqlite3BitvecDestroy(pBt->pHasContent);
   575    575     pBt->pHasContent = 0;
   576    576   }
          577  +
          578  +/*
          579  +** Release all of the apPage[] pages for a cursor.
          580  +*/
          581  +static void btreeReleaseAllCursorPages(BtCursor *pCur){
          582  +  int i;
          583  +  for(i=0; i<=pCur->iPage; i++){
          584  +    releasePage(pCur->apPage[i]);
          585  +    pCur->apPage[i] = 0;
          586  +  }
          587  +  pCur->iPage = -1;
          588  +}
          589  +
   577    590   
   578    591   /*
   579    592   ** Save the current cursor position in the variables BtCursor.nKey 
   580    593   ** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK.
   581    594   **
   582    595   ** The caller must ensure that the cursor is valid (has eState==CURSOR_VALID)
   583    596   ** prior to calling this routine.  
................................................................................
   610    623       }else{
   611    624         rc = SQLITE_NOMEM;
   612    625       }
   613    626     }
   614    627     assert( !pCur->apPage[0]->intKey || !pCur->pKey );
   615    628   
   616    629     if( rc==SQLITE_OK ){
   617         -    int i;
   618         -    for(i=0; i<=pCur->iPage; i++){
   619         -      releasePage(pCur->apPage[i]);
   620         -      pCur->apPage[i] = 0;
   621         -    }
   622         -    pCur->iPage = -1;
          630  +    btreeReleaseAllCursorPages(pCur);
   623    631       pCur->eState = CURSOR_REQUIRESEEK;
   624    632     }
   625    633   
   626    634     invalidateOverflowCache(pCur);
   627    635     return rc;
   628    636   }
   629    637   
................................................................................
   633    641   ** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()).
   634    642   */
   635    643   static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){
   636    644     BtCursor *p;
   637    645     assert( sqlite3_mutex_held(pBt->mutex) );
   638    646     assert( pExcept==0 || pExcept->pBt==pBt );
   639    647     for(p=pBt->pCursor; p; p=p->pNext){
   640         -    if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) && 
   641         -        p->eState==CURSOR_VALID ){
   642         -      int rc = saveCursorPosition(p);
   643         -      if( SQLITE_OK!=rc ){
   644         -        return rc;
          648  +    if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) ){
          649  +      if( p->eState==CURSOR_VALID ){
          650  +        int rc = saveCursorPosition(p);
          651  +        if( SQLITE_OK!=rc ){
          652  +          return rc;
          653  +        }
          654  +      }else{
          655  +        testcase( p->iPage>0 );
          656  +        btreeReleaseAllCursorPages(p);
   645    657         }
   646    658       }
   647    659     }
   648    660     return SQLITE_OK;
   649    661   }
   650    662   
   651    663   /*

Added test/tkt-6bfb98dfc0.test.

            1  +# 2013 March 27
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# This file implements regression tests for SQLite library. Specifically,
           12  +# it tests that ticket [6bfb98dfc0]
           13  +#
           14  +# The final INSERT in the script below reports that the database is
           15  +# corrupt (SQLITE_CORRUPT) and aborts even though the database is not
           16  +# corrupt.
           17  +#
           18  +#    PRAGMA page_size=512;
           19  +#    CREATE TABLE t1(x INTEGER PRIMARY KEY, y);
           20  +#    INSERT INTO t1 VALUES(1,randomblob(400));
           21  +#    INSERT INTO t1 VALUES(2,randomblob(400));
           22  +#    INSERT INTO t1 SELECT x+2, randomblob(400) FROM t1;
           23  +#    INSERT INTO t1 SELECT x+4, randomblob(400) FROM t1;
           24  +#    INSERT INTO t1 SELECT x+8, randomblob(400) FROM t1;
           25  +#    INSERT INTO t1 SELECT x+16, randomblob(400) FROM t1;
           26  +#    INSERT INTO t1 SELECT x+32, randomblob(400) FROM t1;
           27  +#    INSERT INTO t1 SELECT x+64, randomblob(400) FROM t1 WHERE x<10;
           28  +#    CREATE TRIGGER r1 AFTER INSERT ON t1 WHEN new.x=74 BEGIN
           29  +#      DELETE FROM t1;
           30  +#      INSERT INTO t1 VALUES(75, randomblob(400));
           31  +#      INSERT INTO t1 VALUES(76, randomblob(400));
           32  +#    END;
           33  +#    INSERT INTO t1 VALUES(74, randomblob(400));
           34  +#
           35  +
           36  +set testdir [file dirname $argv0]
           37  +source $testdir/tester.tcl
           38  +
           39  +do_test tkt-6bfb98dfc0.100 {
           40  +  db eval {
           41  +    PRAGMA page_size=512;
           42  +    CREATE TABLE t1(x INTEGER PRIMARY KEY, y);
           43  +    INSERT INTO t1 VALUES(1,randomblob(400));
           44  +    INSERT INTO t1 VALUES(2,randomblob(400));
           45  +    INSERT INTO t1 SELECT x+2, randomblob(400) FROM t1;
           46  +    INSERT INTO t1 SELECT x+4, randomblob(400) FROM t1;
           47  +    INSERT INTO t1 SELECT x+8, randomblob(400) FROM t1;
           48  +    INSERT INTO t1 SELECT x+16, randomblob(400) FROM t1;
           49  +    INSERT INTO t1 SELECT x+32, randomblob(400) FROM t1;
           50  +    INSERT INTO t1 SELECT x+64, randomblob(400) FROM t1 WHERE x<10;
           51  +    CREATE TRIGGER r1 AFTER INSERT ON t1 WHEN new.x=74 BEGIN
           52  +      DELETE FROM t1;
           53  +      INSERT INTO t1 VALUES(75, randomblob(400));
           54  +      INSERT INTO t1 VALUES(76, randomblob(400));
           55  +    END;
           56  +    INSERT INTO t1 VALUES(74, randomblob(400));
           57  +    SELECT x, length(y) FROM t1 ORDER BY x;
           58  +  }
           59  +} {75 400 76 400}
           60  +    
           61  +finish_test