SQLite

Check-in [02def8f925]
Login

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

Overview
Comment:If an error occurs in PagerSetPagesize(), set the output variable to the unmodified page-size before returning.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 02def8f92588b8a45dff3976d1e7f9e3f0359b3b
User & Date: dan 2010-08-12 16:36:35.000
Context
2010-08-13
16:38
Do not apply the flattening optimization if the sub-query is DISTINCT. Fix for [e4b8a2ba6e]. (check-in: 497aafd8ed user: dan tags: trunk)
2010-08-12
16:36
If an error occurs in PagerSetPagesize(), set the output variable to the unmodified page-size before returning. (check-in: 02def8f925 user: dan tags: trunk)
11:25
Add coverage tests for pager.c. (check-in: 228c5b16af user: dan tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/pager.c.
3350
3351
3352
3353
3354
3355
3356


3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374

3375
3376
3377
3378

3379
3380


3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392

3393
3394
3395
3396

3397
3398
3399
3400
3401
3402
3403
3404
**
** If the page size is not changed, either because one of the enumerated
** conditions above is not true, the pager was in error state when this
** function was called, or because the memory allocation attempt failed, 
** then *pPageSize is set to the old, retained page size before returning.
*/
int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){


  /* It is not possible to do a full assert_pager_state() here, as this
  ** function may be called from within PagerOpen(), before the state
  ** of the Pager object is internally consistent.
  **
  ** At one point this function returned an error if the pager was in 
  ** PAGER_ERROR state. But since PAGER_ERROR state guarantees that
  ** there is at least one outstanding page reference, this function
  ** is a no-op for that case anyhow.
  */

  u32 pageSize = *pPageSize;
  assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) );
  if( (pPager->memDb==0 || pPager->dbSize==0)
   && sqlite3PcacheRefCount(pPager->pPCache)==0 
   && pageSize && pageSize!=pPager->pageSize 
  ){
    char *pNew;                 /* New temp space */
    i64 nByte = 0;

    if( pPager->eState>PAGER_OPEN && isOpen(pPager->fd) ){
      int rc = sqlite3OsFileSize(pPager->fd, &nByte);
      if( rc!=SQLITE_OK ) return rc;
    }

    pNew = (char *)sqlite3PageMalloc(pageSize);
    if( !pNew ){


      return SQLITE_NOMEM;
    }else{
      pager_reset(pPager);
      pPager->dbSize = nByte/pageSize;
      pPager->pageSize = pageSize;
      sqlite3PageFree(pPager->pTmpSpace);
      pPager->pTmpSpace = pNew;
      sqlite3PcacheSetPageSize(pPager->pPCache, pageSize);
    }
  }

  *pPageSize = pPager->pageSize;

  if( nReserve<0 ) nReserve = pPager->nReserve;
  assert( nReserve>=0 && nReserve<1000 );
  pPager->nReserve = (i16)nReserve;
  pagerReportSize(pPager);

  return SQLITE_OK;
}

/*
** Return a pointer to the "temporary page" buffer held internally
** by the pager.  This is a buffer that is big enough to hold the
** entire content of a database page.  This buffer is used internally
** during rollback and will be overwritten whenever a rollback







>
>


















>

|
<

>
|
|
>
>
|
<










>
|
|
|
|
>
|







3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379

3380
3381
3382
3383
3384
3385
3386

3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
**
** If the page size is not changed, either because one of the enumerated
** conditions above is not true, the pager was in error state when this
** function was called, or because the memory allocation attempt failed, 
** then *pPageSize is set to the old, retained page size before returning.
*/
int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){
  int rc = SQLITE_OK;

  /* It is not possible to do a full assert_pager_state() here, as this
  ** function may be called from within PagerOpen(), before the state
  ** of the Pager object is internally consistent.
  **
  ** At one point this function returned an error if the pager was in 
  ** PAGER_ERROR state. But since PAGER_ERROR state guarantees that
  ** there is at least one outstanding page reference, this function
  ** is a no-op for that case anyhow.
  */

  u32 pageSize = *pPageSize;
  assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) );
  if( (pPager->memDb==0 || pPager->dbSize==0)
   && sqlite3PcacheRefCount(pPager->pPCache)==0 
   && pageSize && pageSize!=pPager->pageSize 
  ){
    char *pNew;                 /* New temp space */
    i64 nByte = 0;

    if( pPager->eState>PAGER_OPEN && isOpen(pPager->fd) ){
      rc = sqlite3OsFileSize(pPager->fd, &nByte);

    }
    if( rc==SQLITE_OK ){
      pNew = (char *)sqlite3PageMalloc(pageSize);
      if( !pNew ) rc = SQLITE_NOMEM;
    }

    if( rc==SQLITE_OK ){

      pager_reset(pPager);
      pPager->dbSize = nByte/pageSize;
      pPager->pageSize = pageSize;
      sqlite3PageFree(pPager->pTmpSpace);
      pPager->pTmpSpace = pNew;
      sqlite3PcacheSetPageSize(pPager->pPCache, pageSize);
    }
  }

  *pPageSize = pPager->pageSize;
  if( rc==SQLITE_OK ){
    if( nReserve<0 ) nReserve = pPager->nReserve;
    assert( nReserve>=0 && nReserve<1000 );
    pPager->nReserve = (i16)nReserve;
    pagerReportSize(pPager);
  }
  return rc;
}

/*
** Return a pointer to the "temporary page" buffer held internally
** by the pager.  This is a buffer that is big enough to hold the
** entire content of a database page.  This buffer is used internally
** during rollback and will be overwritten whenever a rollback
Changes to test/pager1.test.
2323
2324
2325
2326
2327
2328
2329



















2330
2331
2332
  do_test pager1-28.$tn.17 { file exists test.db-journal } 1

  do_test pager1-28.$tn.17 { csql2 { COMMIT } } {1 {database is locked}}
  do_test pager1-28-$tn.18 { code1 { read $channel } } c
  do_test pager1-28-$tn.19 { code1 { close $channel } } {}
  do_test pager1-28.$tn.20 { sql2 { COMMIT } } {}
}





















finish_test







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



2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
  do_test pager1-28.$tn.17 { file exists test.db-journal } 1

  do_test pager1-28.$tn.17 { csql2 { COMMIT } } {1 {database is locked}}
  do_test pager1-28-$tn.18 { code1 { read $channel } } c
  do_test pager1-28-$tn.19 { code1 { close $channel } } {}
  do_test pager1-28.$tn.20 { sql2 { COMMIT } } {}
}

do_test pager1-29.1 {
  faultsim_delete_and_reopen
  execsql {
    PRAGMA page_size = 1024;
    PRAGMA auto_vacuum = full;
    PRAGMA locking_mode=exclusive;
    CREATE TABLE t1(a, b);
    INSERT INTO t1 VALUES(1, 2);
  }
  file size test.db
} [expr 1024*3]
do_test pager1-29.2 {
  execsql {
    PRAGMA page_size = 4096;
    VACUUM;
  }
  file size test.db
} [expr 4096*3]


finish_test
Changes to test/pagerfault.test.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
proc a_string {n} {
  global a_string_counter
  incr a_string_counter
  string range [string repeat "${a_string_counter}." $n] 1 $n
}
db func a_string a_string

if 1 {

#-------------------------------------------------------------------------
# Test fault-injection while rolling back a hot-journal file.
#
do_test pagerfault-1-pre1 {
  execsql {
    PRAGMA journal_mode = DELETE;
    PRAGMA cache_size = 10;







<
<







24
25
26
27
28
29
30


31
32
33
34
35
36
37
proc a_string {n} {
  global a_string_counter
  incr a_string_counter
  string range [string repeat "${a_string_counter}." $n] 1 $n
}
db func a_string a_string



#-------------------------------------------------------------------------
# Test fault-injection while rolling back a hot-journal file.
#
do_test pagerfault-1-pre1 {
  execsql {
    PRAGMA journal_mode = DELETE;
    PRAGMA cache_size = 10;
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135

1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166

1167
1168
1169
1170










1171




















1172
} -test {
  faultsim_test_result {0 {}} \
    {1 {unable to open a temporary database file for storing temporary tables}}
  set ic [db eval { PRAGMA temp.integrity_check }]
  if {$ic != "ok"} { error "Integrity check: $ic" }
}

}

proc lockrows {n} {
  if {$n==0} { return "" }
  db eval { SELECT * FROM t1 WHERE oid = $n } { 
    return [lockrows [expr {$n-1}]]
  }
}


do_test pagerfault-25-pre1 {
  faultsim_delete_and_reopen
  db func a_string a_string
  execsql {
    PRAGMA page_size = 1024;
    PRAGMA auto_vacuum = 0;
    CREATE TABLE t1(a);
    INSERT INTO t1 VALUES(a_string(500));
    INSERT INTO t1 SELECT a_string(500) FROM t1;
    INSERT INTO t1 SELECT a_string(500) FROM t1;
    INSERT INTO t1 SELECT a_string(500) FROM t1;
    INSERT INTO t1 SELECT a_string(500) FROM t1;
    INSERT INTO t1 SELECT a_string(500) FROM t1;
  }
  faultsim_save_and_close
} {}
do_faultsim_test pagerfault-25 -faults full -prep {
  faultsim_restore_and_reopen
  db func a_string a_string
  set ::channel [db incrblob -readonly t1 a 1]
  execsql { 
    PRAGMA cache_size = 10;
    BEGIN;
      INSERT INTO t1 VALUES(a_string(3000));
      INSERT INTO t1 VALUES(a_string(3000));
  }
} -body {
  lockrows 30
} -test {
  catch { lockrows 30 }

  close $::channel
  faultsim_test_result {0 {}} 
}
































finish_test







<
<






>

















|













>




>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

1119
1120
1121
1122
1123
1124
1125


1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
} -test {
  faultsim_test_result {0 {}} \
    {1 {unable to open a temporary database file for storing temporary tables}}
  set ic [db eval { PRAGMA temp.integrity_check }]
  if {$ic != "ok"} { error "Integrity check: $ic" }
}



proc lockrows {n} {
  if {$n==0} { return "" }
  db eval { SELECT * FROM t1 WHERE oid = $n } { 
    return [lockrows [expr {$n-1}]]
  }
}


do_test pagerfault-25-pre1 {
  faultsim_delete_and_reopen
  db func a_string a_string
  execsql {
    PRAGMA page_size = 1024;
    PRAGMA auto_vacuum = 0;
    CREATE TABLE t1(a);
    INSERT INTO t1 VALUES(a_string(500));
    INSERT INTO t1 SELECT a_string(500) FROM t1;
    INSERT INTO t1 SELECT a_string(500) FROM t1;
    INSERT INTO t1 SELECT a_string(500) FROM t1;
    INSERT INTO t1 SELECT a_string(500) FROM t1;
    INSERT INTO t1 SELECT a_string(500) FROM t1;
  }
  faultsim_save_and_close
} {}
do_faultsim_test pagerfault-25 -prep {
  faultsim_restore_and_reopen
  db func a_string a_string
  set ::channel [db incrblob -readonly t1 a 1]
  execsql { 
    PRAGMA cache_size = 10;
    BEGIN;
      INSERT INTO t1 VALUES(a_string(3000));
      INSERT INTO t1 VALUES(a_string(3000));
  }
} -body {
  lockrows 30
} -test {
  catch { lockrows 30 }
  catch { db eval COMMIT }
  close $::channel
  faultsim_test_result {0 {}} 
}

do_faultsim_test pagerfault-26 -prep {
  faultsim_delete_and_reopen
  execsql {
    PRAGMA page_size = 1024;
    PRAGMA journal_mode = truncate;
    PRAGMA auto_vacuum = full;
    PRAGMA locking_mode=exclusive;
    CREATE TABLE t1(a, b);
    INSERT INTO t1 VALUES(1, 2);
    PRAGMA page_size = 4096;
  }
} -body {
  execsql {
    VACUUM;
  }
} -test {
  faultsim_test_result {0 {}}

  set contents [db eval {SELECT * FROM t1}]
  if {$contents != "1 2"} { error "Bad database contents ($contents)" }

  set sz [file size test.db]
  if {$testrc!=0 && $sz!=1024*3 && $sz!=4096*3} { 
    error "Expected file size to be 3072 or 12288 bytes - actual size $sz bytes"
  }
  if {$testrc==0 && $sz!=4096*3} { 
    error "Expected file size to be 12288 bytes - actual size $sz bytes"
  }
} 


finish_test