/ Check-in [db54a946]
Login

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

Overview
Comment:Minor bugfixes for incrblob mode. (CVS 3903)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:db54a9466e3bea9c03740ce0b755cfa02bafaccd
User & Date: danielk1977 2007-05-03 11:43:33
Context
2007-05-03
11:43
Minor bugfixes for incrblob mode. (CVS 3904) check-in: b84d597c user: danielk1977 tags: trunk
11:43
Minor bugfixes for incrblob mode. (CVS 3903) check-in: db54a946 user: danielk1977 tags: trunk
2007-05-02
17:54
Allow CREATE TABLE to occur while other queries are running. DROP TABLE is still prohibited, however, since we do not want to delete a table out from under an running query. (CVS 3902) check-in: 5b4bf1fc user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/btree.c.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
....
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
....
5758
5759
5760
5761
5762
5763
5764













5765
5766
5767
5768
5769
5770
5771
....
6939
6940
6941
6942
6943
6944
6945
6946
6947
6948
6949
6950
6951
6952
6953
6954
6955
6956
6957
6958
6959
6960
6961
6962
6963
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree.c,v 1.368 2007/05/02 17:54:56 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
**
**     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
**     "Sorting And Searching", pages 473-480. Addison-Wesley
**     Publishing Company, Reading, Massachusetts.
................................................................................
    Pgno iGuess = ovfl+1;
    u8 eType;

    while( PTRMAP_ISPAGE(pBt, iGuess) || iGuess==PENDING_BYTE_PAGE(pBt) ){
      iGuess++;
    }

    if( iGuess<sqlite3PagerPagecount(pBt->pPager) ){
      rc = ptrmapGet(pBt, iGuess, &eType, &pgno);
      if( rc!=SQLITE_OK ){
        return rc;
      }
      if( eType==PTRMAP_OVERFLOW2 && pgno==ovfl ){
        next = iGuess;
      }
................................................................................
#ifdef SQLITE_OMIT_AUTOVACUUM
  rc = allocateBtreePage(pBt, &pRoot, &pgnoRoot, 1, 0);
  if( rc ) return rc;
#else
  if( pBt->autoVacuum ){
    Pgno pgnoMove;      /* Move a page here to make room for the root-page */
    MemPage *pPageMove; /* The page to move to. */














    /* Read the value of meta[3] from the database to determine where the
    ** root page of the new table should go. meta[3] is the largest root-page
    ** created so far, so the new root-page is (meta[3]+1).
    */
    rc = sqlite3BtreeGetMeta(p, 4, &pgnoRoot);
    if( rc!=SQLITE_OK ) return rc;
................................................................................
** INTKEY table currently pointing at a valid table entry. 
** This function modifies the data stored as part of that entry.
** Only the data content may only be modified, it is not possible
** to change the length of the data stored.
*/
int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, const void *z){
  BtShared *pBt = pCsr->pBtree->pBt;
  int rc;

  u32 iRem = amt;        /* Remaining bytes to write */
  u8 *zRem = (u8 *)z;    /* Pointer to data not yet written */
  u32 iOffset = offset;  /* Offset from traversal point to start of write */

  Pgno iIdx = 0;         /* Index of overflow page in pCsr->aOverflow */
  Pgno iOvfl;            /* Page number for next overflow page */
  int ovflSize;          /* Bytes of data per overflow page. */

  CellInfo *pInfo;

  /* Check some preconditions: 
  **   (a) a write-transaction is open, 
  **   (b) the cursor is open for writing,
  **   (c) there is no read-lock on the table being modified and
  **   (d) the cursor points at a valid row of an intKey table.
  */







|







 







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>







 







<
<
<
<
<
<
<
<
<
<
<







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
....
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
....
5758
5759
5760
5761
5762
5763
5764
5765
5766
5767
5768
5769
5770
5771
5772
5773
5774
5775
5776
5777
5778
5779
5780
5781
5782
5783
5784
....
6952
6953
6954
6955
6956
6957
6958











6959
6960
6961
6962
6963
6964
6965
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree.c,v 1.369 2007/05/03 11:43:33 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
**
**     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
**     "Sorting And Searching", pages 473-480. Addison-Wesley
**     Publishing Company, Reading, Massachusetts.
................................................................................
    Pgno iGuess = ovfl+1;
    u8 eType;

    while( PTRMAP_ISPAGE(pBt, iGuess) || iGuess==PENDING_BYTE_PAGE(pBt) ){
      iGuess++;
    }

    if( iGuess<=sqlite3PagerPagecount(pBt->pPager) ){
      rc = ptrmapGet(pBt, iGuess, &eType, &pgno);
      if( rc!=SQLITE_OK ){
        return rc;
      }
      if( eType==PTRMAP_OVERFLOW2 && pgno==ovfl ){
        next = iGuess;
      }
................................................................................
#ifdef SQLITE_OMIT_AUTOVACUUM
  rc = allocateBtreePage(pBt, &pRoot, &pgnoRoot, 1, 0);
  if( rc ) return rc;
#else
  if( pBt->autoVacuum ){
    Pgno pgnoMove;      /* Move a page here to make room for the root-page */
    MemPage *pPageMove; /* The page to move to. */

#ifndef SQLITE_OMIT_INCRBLOB
    /* Creating a new table may probably require moving an existing database
    ** to make room for the new tables root page. In case this page turns
    ** out to be an overflow page, delete all overflow page-map caches
    ** held by open cursors.
    */
    BtCursor *pCur;
    for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
      sqliteFree(pCur->aOverflow);
      pCur->aOverflow = 0;
    }
#endif

    /* Read the value of meta[3] from the database to determine where the
    ** root page of the new table should go. meta[3] is the largest root-page
    ** created so far, so the new root-page is (meta[3]+1).
    */
    rc = sqlite3BtreeGetMeta(p, 4, &pgnoRoot);
    if( rc!=SQLITE_OK ) return rc;
................................................................................
** INTKEY table currently pointing at a valid table entry. 
** This function modifies the data stored as part of that entry.
** Only the data content may only be modified, it is not possible
** to change the length of the data stored.
*/
int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, const void *z){
  BtShared *pBt = pCsr->pBtree->pBt;












  /* Check some preconditions: 
  **   (a) a write-transaction is open, 
  **   (b) the cursor is open for writing,
  **   (c) there is no read-lock on the table being modified and
  **   (d) the cursor points at a valid row of an intKey table.
  */

Changes to src/vdbeblob.c.

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
..
86
87
88
89
90
91
92





93
94
95
96
97
98

99
100
101
102
103
104
105
106
107
108
109
110
111

112
113
114
115
116
117
118
...
140
141
142
143
144
145
146





147
148
149
150
151
152
153
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
**
** $Id: vdbeblob.c,v 1.2 2007/05/02 16:48:37 danielk1977 Exp $
*/

#include "sqliteInt.h"
#include "vdbeInt.h"

#ifndef SQLITE_OMIT_INCRBLOB

................................................................................

  do {
    Parse sParse;
    Table *pTab;

    memset(&sParse, 0, sizeof(Parse));
    sParse.db = db;






    pTab = sqlite3LocateTable(&sParse, zTable, zDb);
    if( !pTab ){
      sqlite3Error(db, sParse.rc, "%s", sParse.zErrMsg);
      sqliteFree(sParse.zErrMsg);
      rc = sParse.rc;

      goto blob_open_out;
    }

    /* Now search pTab for the exact column. */
    for(iCol=0; iCol < pTab->nCol; iCol++) {
      if( sqlite3StrICmp(pTab->aCol[iCol].zName, zColumn)==0 ){
        break;
      }
    }
    if( iCol==pTab->nCol ){
      sqlite3Error(db, SQLITE_ERROR, "no such column: %s", zColumn);
      sqliteFree(sParse.zErrMsg);
      rc = SQLITE_ERROR;

      goto blob_open_out;
    }

    v = sqlite3VdbeCreate(db);
    if( v ){
      int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
      sqlite3VdbeAddOpList(v, sizeof(openBlob)/sizeof(VdbeOpList), openBlob);
................................................................................
      ** always return an SQL NULL. This is useful because it means
      ** we can invoke OP_Column to fill in the vdbe cursors type 
      ** and offset cache without causing any IO.
      */
      sqlite3VdbeChangeP2(v, 5, pTab->nCol+1);
      sqlite3VdbeMakeReady(v, 1, 0, 1, 0);
    }






    sqlite3_bind_int64((sqlite3_stmt *)v, 1, iRow);
    rc = sqlite3_step((sqlite3_stmt *)v);
    if( rc!=SQLITE_ROW ){
      nAttempt++;
      rc = sqlite3_finalize((sqlite3_stmt *)v);
      v = 0;







|







 







>
>
>
>
>






>













>







 







>
>
>
>
>







6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
..
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
...
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
**
** $Id: vdbeblob.c,v 1.3 2007/05/03 11:43:33 danielk1977 Exp $
*/

#include "sqliteInt.h"
#include "vdbeInt.h"

#ifndef SQLITE_OMIT_INCRBLOB

................................................................................

  do {
    Parse sParse;
    Table *pTab;

    memset(&sParse, 0, sizeof(Parse));
    sParse.db = db;

    rc = sqlite3SafetyOn(db);
    if( rc!=SQLITE_OK ){
      return rc;
    }

    pTab = sqlite3LocateTable(&sParse, zTable, zDb);
    if( !pTab ){
      sqlite3Error(db, sParse.rc, "%s", sParse.zErrMsg);
      sqliteFree(sParse.zErrMsg);
      rc = sParse.rc;
      sqlite3SafetyOff(db);
      goto blob_open_out;
    }

    /* Now search pTab for the exact column. */
    for(iCol=0; iCol < pTab->nCol; iCol++) {
      if( sqlite3StrICmp(pTab->aCol[iCol].zName, zColumn)==0 ){
        break;
      }
    }
    if( iCol==pTab->nCol ){
      sqlite3Error(db, SQLITE_ERROR, "no such column: %s", zColumn);
      sqliteFree(sParse.zErrMsg);
      rc = SQLITE_ERROR;
      sqlite3SafetyOff(db);
      goto blob_open_out;
    }

    v = sqlite3VdbeCreate(db);
    if( v ){
      int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
      sqlite3VdbeAddOpList(v, sizeof(openBlob)/sizeof(VdbeOpList), openBlob);
................................................................................
      ** always return an SQL NULL. This is useful because it means
      ** we can invoke OP_Column to fill in the vdbe cursors type 
      ** and offset cache without causing any IO.
      */
      sqlite3VdbeChangeP2(v, 5, pTab->nCol+1);
      sqlite3VdbeMakeReady(v, 1, 0, 1, 0);
    }

    rc = sqlite3SafetyOff(db);
    if( rc!=SQLITE_OK ){
      return rc;
    }

    sqlite3_bind_int64((sqlite3_stmt *)v, 1, iRow);
    rc = sqlite3_step((sqlite3_stmt *)v);
    if( rc!=SQLITE_ROW ){
      nAttempt++;
      rc = sqlite3_finalize((sqlite3_stmt *)v);
      v = 0;

Changes to test/incrblob.test.

5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
..
45
46
47
48
49
50
51
52
53

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82



























































#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# $Id: incrblob.test,v 1.2 2007/05/02 13:16:31 danielk1977 Exp $


set testdir [file dirname $argv0]
source $testdir/tester.tcl

do_test incrblob-1.1 {
  execsql {
    CREATE TABLE blobs(k PRIMARY KEY, v BLOB);
................................................................................
do_test incrblob-1.2.6 {
  execsql {
    SELECT v FROM blobs WHERE rowid = 1;
  }
} {1234567890}

#--------------------------------------------------------------------
# Test cases incrblob-2.X check that it is possible to read and write
# regions of a blob that lie on overflow pages.

do_test incrblob-2.1 {
  set ::str "[string repeat . 10000]"
  execsql {
    INSERT INTO blobs(rowid, k, v) VALUES(3, 'three', $::str);
  }
} {}

do_test incrblob-2.2 {
  set ::blob [db incrblob blobs v 3]
  seek $::blob 8500
  read $::blob 10
} {..........}

do_test incrblob-2.3 {
  seek $::blob 8500
  puts -nonewline $::blob 1234567890
} {}

do_test incrblob-2.4 {
  seek $::blob 8496
  read $::blob 10
} {....123456}

do_test incrblob-2.10 {
  close $::blob
} {}

finish_test



































































|
>







 







|

>
|






|




<
|



<
|



<
|



<

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
..
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

68
69
70
71

72
73
74
75

76
77
78
79

80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# $Id: incrblob.test,v 1.3 2007/05/03 11:43:35 danielk1977 Exp $
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

do_test incrblob-1.1 {
  execsql {
    CREATE TABLE blobs(k PRIMARY KEY, v BLOB);
................................................................................
do_test incrblob-1.2.6 {
  execsql {
    SELECT v FROM blobs WHERE rowid = 1;
  }
} {1234567890}

#--------------------------------------------------------------------
# Test cases incrblob-1.3.X check that it is possible to read and write
# regions of a blob that lie on overflow pages.
#
do_test incrblob-1.3.1 {
  set ::str "[string repeat . 10000]"
  execsql {
    INSERT INTO blobs(rowid, k, v) VALUES(3, 'three', $::str);
  }
} {}

do_test incrblob-1.3.2 {
  set ::blob [db incrblob blobs v 3]
  seek $::blob 8500
  read $::blob 10
} {..........}

do_test incrblob-1.3.3 {
  seek $::blob 8500
  puts -nonewline $::blob 1234567890
} {}

do_test incrblob-1.3.4 {
  seek $::blob 8496
  read $::blob 10
} {....123456}

do_test incrblob-1.3.10 {
  close $::blob
} {}



#------------------------------------------------------------------------
# incrblob-2.*: Test seeking in an incremental blob can use ptrmap pages.
#
proc nRead {db} {
  set bt [btree_from_db $db]
  array set stats [btree_pager_stats $bt]
  return $stats(read)
}

foreach AutoVacuumMode [list 0 1] {

  db close
  file delete -force test.db test.db-journal

  sqlite3 db test.db
  execsql "PRAGMA auto_vacuum = $AutoVacuumMode"

  do_test incrblob-2.$AutoVacuumMode.1 {
    set ::str [string repeat abcdefghij 2900]
    execsql {
      BEGIN;
      CREATE TABLE blobs(k PRIMARY KEY, v BLOB);
      DELETE FROM blobs;
      INSERT INTO blobs VALUES('one', $::str || randstr(500,500));
      COMMIT;
    }
    expr [file size test.db]/1024
  } [expr 31 + $AutoVacuumMode]

  do_test incrblob-2.$AutoVacuumMode.2 {
    execsql {
      PRAGMA auto_vacuum;
    }
  } $AutoVacuumMode

  do_test incrblob-2.$AutoVacuumMode.3 {
    # Open and close the db to make sure the page cache is empty.
    db close
    sqlite3 db test.db
  
    # Read the last 20 bytes of the blob via a blob handle.
    set ::blob [db incrblob blobs v 1]
    seek $::blob -20 end
    set ::fragment [read $::blob]
    close $::blob
  
    # If the database is not in auto-vacuum mode, the whole of
    # the overflow-chain must be scanned. In auto-vacuum mode,
    # sqlite uses the ptrmap pages to avoid reading the other pages.
    #
    nRead db
  } [expr $AutoVacuumMode ? 4 : 30]

  do_test incrblob-2.3 {
    string range [db one {SELECT v FROM blobs}] end-19 end
  } $::fragment
}

finish_test