/ Check-in [af679f61]
Login

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

Overview
Comment:After an OP_NullRow is executed on a cursor, cause any subsequent OP_Next or OP_Prev to behave as if there were no more rows to traverse. Ticket #3424. (CVS 5782)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:af679f6170b346fe61df7dae963b2a2853e62a62
User & Date: danielk1977 2008-10-08 17:58:49
Context
2008-10-09
14:45
Minor cleanup of the new "status" command on the TCL bindings. (CVS 5783) check-in: ec01bd72 user: drh tags: trunk
2008-10-08
17:58
After an OP_NullRow is executed on a cursor, cause any subsequent OP_Next or OP_Prev to behave as if there were no more rows to traverse. Ticket #3424. (CVS 5782) check-in: af679f61 user: danielk1977 tags: trunk
2008-10-07
23:46
Add the experimental sqlite3_stmt_status() interface. (CVS 5781) check-in: de473efb user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btree.c.

     5      5   ** a legal notice, here is a blessing:
     6      6   **
     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12         -** $Id: btree.c,v 1.524 2008/09/30 17:18:17 drh Exp $
           12  +** $Id: btree.c,v 1.525 2008/10/08 17:58:49 danielk1977 Exp $
    13     13   **
    14     14   ** This file implements a external (disk-based) database using BTrees.
    15     15   ** See the header comment on "btreeInt.h" for additional information.
    16     16   ** Including a description of file format and an overview of operation.
    17     17   */
    18     18   #include "btreeInt.h"
    19     19   
................................................................................
   364    364     }
   365    365     return SQLITE_OK;
   366    366   }
   367    367   
   368    368   /*
   369    369   ** Clear the current cursor position.
   370    370   */
   371         -static void clearCursorPosition(BtCursor *pCur){
          371  +void sqlite3BtreeClearCursor(BtCursor *pCur){
   372    372     assert( cursorHoldsMutex(pCur) );
   373    373     sqlite3_free(pCur->pKey);
   374    374     pCur->pKey = 0;
   375    375     pCur->eState = CURSOR_INVALID;
   376    376   }
   377    377   
   378    378   /*
................................................................................
  2590   2590   ** save the state of the cursor.  The cursor must be
  2591   2591   ** invalidated.
  2592   2592   */
  2593   2593   void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){
  2594   2594     BtCursor *p;
  2595   2595     sqlite3BtreeEnter(pBtree);
  2596   2596     for(p=pBtree->pBt->pCursor; p; p=p->pNext){
  2597         -    clearCursorPosition(p);
         2597  +    sqlite3BtreeClearCursor(p);
  2598   2598       p->eState = CURSOR_FAULT;
  2599   2599       p->skip = errCode;
  2600   2600     }
  2601   2601     sqlite3BtreeLeave(pBtree);
  2602   2602   }
  2603   2603   
  2604   2604   /*
................................................................................
  2863   2863   int sqlite3BtreeCloseCursor(BtCursor *pCur){
  2864   2864     Btree *pBtree = pCur->pBtree;
  2865   2865     if( pBtree ){
  2866   2866       int i;
  2867   2867       BtShared *pBt = pCur->pBt;
  2868   2868       sqlite3BtreeEnter(pBtree);
  2869   2869       pBt->db = pBtree->db;
  2870         -    clearCursorPosition(pCur);
         2870  +    sqlite3BtreeClearCursor(pCur);
  2871   2871       if( pCur->pPrev ){
  2872   2872         pCur->pPrev->pNext = pCur->pNext;
  2873   2873       }else{
  2874   2874         pBt->pCursor = pCur->pNext;
  2875   2875       }
  2876   2876       if( pCur->pNext ){
  2877   2877         pCur->pNext->pPrev = pCur->pPrev;
................................................................................
  3522   3522     assert( CURSOR_INVALID < CURSOR_REQUIRESEEK );
  3523   3523     assert( CURSOR_VALID   < CURSOR_REQUIRESEEK );
  3524   3524     assert( CURSOR_FAULT   > CURSOR_REQUIRESEEK );
  3525   3525     if( pCur->eState>=CURSOR_REQUIRESEEK ){
  3526   3526       if( pCur->eState==CURSOR_FAULT ){
  3527   3527         return pCur->skip;
  3528   3528       }
  3529         -    clearCursorPosition(pCur);
         3529  +    sqlite3BtreeClearCursor(pCur);
  3530   3530     }
  3531   3531   
  3532   3532     if( pCur->iPage>=0 ){
  3533   3533       int i;
  3534   3534       for(i=1; i<=pCur->iPage; i++){
  3535   3535         releasePage(pCur->apPage[i]);
  3536   3536       }
................................................................................
  5767   5767       return SQLITE_LOCKED; /* The table pCur points to has a read lock */
  5768   5768     }
  5769   5769     if( pCur->eState==CURSOR_FAULT ){
  5770   5770       return pCur->skip;
  5771   5771     }
  5772   5772   
  5773   5773     /* Save the positions of any other cursors open on this table */
  5774         -  clearCursorPosition(pCur);
         5774  +  sqlite3BtreeClearCursor(pCur);
  5775   5775     if( 
  5776   5776       SQLITE_OK!=(rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur)) ||
  5777   5777       SQLITE_OK!=(rc = sqlite3BtreeMoveto(pCur, pKey, nKey, appendBias, &loc))
  5778   5778     ){
  5779   5779       return rc;
  5780   5780     }
  5781   5781   

Changes to src/btree.h.

     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This header file defines the interface that the sqlite B-Tree file
    13     13   ** subsystem.  See comments in the source code for a detailed description
    14     14   ** of what each interface routine does.
    15     15   **
    16         -** @(#) $Id: btree.h,v 1.103 2008/08/13 19:11:48 drh Exp $
           16  +** @(#) $Id: btree.h,v 1.104 2008/10/08 17:58:49 danielk1977 Exp $
    17     17   */
    18     18   #ifndef _BTREE_H_
    19     19   #define _BTREE_H_
    20     20   
    21     21   /* TODO: This definition is just included so other modules compile. It
    22     22   ** needs to be revisited.
    23     23   */
................................................................................
   166    166   int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
   167    167   
   168    168   char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
   169    169   struct Pager *sqlite3BtreePager(Btree*);
   170    170   
   171    171   int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
   172    172   void sqlite3BtreeCacheOverflow(BtCursor *);
          173  +void sqlite3BtreeClearCursor(BtCursor *);
   173    174   
   174    175   #ifdef SQLITE_TEST
   175    176   int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
   176    177   void sqlite3BtreeCursorList(Btree*);
   177    178   #endif
   178    179   
   179    180   /*

Changes to src/vdbe.c.

    39     39   **
    40     40   ** Various scripts scan this source file in order to generate HTML
    41     41   ** documentation, headers files, or other derived files.  The formatting
    42     42   ** of the code in this file is, therefore, important.  See other comments
    43     43   ** in this file for details.  If in doubt, do not deviate from existing
    44     44   ** commenting and indentation practices when changing or adding code.
    45     45   **
    46         -** $Id: vdbe.c,v 1.781 2008/10/07 23:46:38 drh Exp $
           46  +** $Id: vdbe.c,v 1.782 2008/10/08 17:58:49 danielk1977 Exp $
    47     47   */
    48     48   #include "sqliteInt.h"
    49     49   #include <ctype.h>
    50     50   #include "vdbeInt.h"
    51     51   
    52     52   /*
    53     53   ** The following global variable is incremented every time a cursor
................................................................................
  3688   3688     Cursor *pC;
  3689   3689   
  3690   3690     assert( i>=0 && i<p->nCursor );
  3691   3691     pC = p->apCsr[i];
  3692   3692     assert( pC!=0 );
  3693   3693     pC->nullRow = 1;
  3694   3694     pC->rowidIsValid = 0;
         3695  +  if( pC->pCursor ){
         3696  +    sqlite3BtreeClearCursor(pC->pCursor);
         3697  +  }
  3695   3698     break;
  3696   3699   }
  3697   3700   
  3698   3701   /* Opcode: Last P1 P2 * * *
  3699   3702   **
  3700   3703   ** The next use of the Rowid or Column or Next instruction for P1 
  3701   3704   ** will refer to the last entry in the database table or index.

Added test/tkt3424.test.

            1  +# 2008 October 06
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +#
           12  +#
           13  +# $Id: tkt3424.test,v 1.1 2008/10/08 17:58:50 danielk1977 Exp $
           14  +
           15  +set testdir [file dirname $argv0]
           16  +source $testdir/tester.tcl
           17  +
           18  +do_test tkt3424-1.1 {
           19  +  execsql {
           20  +    CREATE TABLE names(id INTEGER, data TEXT, code TEXT);
           21  +    INSERT INTO names VALUES(1,'E1','AAA');
           22  +    INSERT INTO names VALUES(2,NULL,'BBB');
           23  +
           24  +    CREATE TABLE orig(code TEXT, data TEXT);
           25  +    INSERT INTO orig VALUES('AAA','E1');
           26  +    INSERT INTO orig VALUES('AAA','E2');
           27  +    INSERT INTO orig VALUES('AAA','E3');
           28  +    INSERT INTO orig VALUES('AAA','E4');
           29  +    INSERT INTO orig VALUES('AAA','E5');
           30  +  }
           31  +} {}
           32  +
           33  +do_test tkt3424-1.2 {
           34  +  execsql {
           35  +    SELECT * FROM 
           36  +    names LEFT OUTER JOIN orig
           37  +    ON names.data = orig.data AND names.code = orig.code;
           38  +  }
           39  +} {1 E1 AAA AAA E1 2 {} BBB {} {}}
           40  +
           41  +do_test tkt3424-1.3 {
           42  +  execsql { CREATE INDEX udx_orig_code_data ON orig(code, data) }
           43  +} {}
           44  +
           45  +do_test tkt3424-1.4 {
           46  +  execsql {
           47  +    SELECT * FROM 
           48  +    names LEFT OUTER JOIN orig
           49  +    ON names.data = orig.data AND names.code = orig.code;
           50  +  }
           51  +} {1 E1 AAA AAA E1 2 {} BBB {} {}}
           52  +
           53  +finish_test
           54  +