/ Check-in [d915718d]
Login

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

Overview
Comment:Increase test coverage of new savepoint code. (CVS 6040)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:d915718d0b346982d686d131a159b67e28fc02a8
User & Date: danielk1977 2008-12-18 18:31:39
Context
2008-12-18
22:25
Fix the Oracle and MS-Sql command-line terminator logic in the CLI. Ticket #3544. (CVS 6041) check-in: dcc8935f user: drh tags: trunk
18:31
Increase test coverage of new savepoint code. (CVS 6040) check-in: d915718d user: danielk1977 tags: trunk
15:45
Add savepoint2.test, a file containing savepoint tests similar to tests in trans.test and avtrans.test. And a few savepoint bug fixes. (CVS 6039) check-in: 98a53d91 user: danielk1977 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/pager.c.

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
918
919
920
921
922
923
924





925
926
927
928
929
930
931
932
933
934
935
936
937




938
939
940
941
942
943
944
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.516 2008/12/18 15:45:07 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"

/*
** Macros for troubleshooting.  Normally turned off
*/
................................................................................
** to access those pages will likely result in a coredump.
*/
static void pager_reset(Pager *pPager){
  if( pPager->errCode ) return;
  sqlite3PcacheClear(pPager->pPCache);
}






static void releaseAllSavepoint(Pager *pPager){
  int ii;
  for(ii=0; ii<pPager->nSavepoint; ii++){
    sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint);
  }
  if( !pPager->exclusiveMode ){
    sqlite3OsClose(pPager->sjfd);
  }
  sqlite3_free(pPager->aSavepoint);
  pPager->aSavepoint = 0;
  pPager->nSavepoint = 0;
}





static int addToSavepointBitvecs(Pager *pPager, Pgno pgno){
  int ii;
  for(ii=0; ii<pPager->nSavepoint; ii++){
    PagerSavepoint *p = &pPager->aSavepoint[ii];
    if( pgno<=p->nOrig ){
      /* TODO: malloc() failure handling */
      sqlite3BitvecSet(p->pInSavepoint, pgno);







|







 







>
>
>
>
>













>
>
>
>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.517 2008/12/18 18:31:39 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"

/*
** Macros for troubleshooting.  Normally turned off
*/
................................................................................
** to access those pages will likely result in a coredump.
*/
static void pager_reset(Pager *pPager){
  if( pPager->errCode ) return;
  sqlite3PcacheClear(pPager->pPCache);
}

/*
** Free all structures in the Pager.aSavepoint[] array and set both
** Pager.aSavepoint and Pager.nSavepoint to zero. Close the sub-journal
** if it is open and the pager is not in exclusive mode.
*/
static void releaseAllSavepoint(Pager *pPager){
  int ii;
  for(ii=0; ii<pPager->nSavepoint; ii++){
    sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint);
  }
  if( !pPager->exclusiveMode ){
    sqlite3OsClose(pPager->sjfd);
  }
  sqlite3_free(pPager->aSavepoint);
  pPager->aSavepoint = 0;
  pPager->nSavepoint = 0;
}

/*
** Set the bit number pgno in the PagerSavepoint.pInSavepoint bitvecs of
** all open savepoints.
*/
static int addToSavepointBitvecs(Pager *pPager, Pgno pgno){
  int ii;
  for(ii=0; ii<pPager->nSavepoint; ii++){
    PagerSavepoint *p = &pPager->aSavepoint[ii];
    if( pgno<=p->nOrig ){
      /* TODO: malloc() failure handling */
      sqlite3BitvecSet(p->pInSavepoint, pgno);

Changes to src/vdbe.c.

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
....
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
....
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474


2475
2476
2477
2478
2479
2480
2481
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.804 2008/12/17 17:30:26 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
** The following global variable is incremented every time a cursor
................................................................................
  */
  assert( db->pSavepoint==0 || db->autoCommit==0 );
  assert( p1==SAVEPOINT_BEGIN||p1==SAVEPOINT_RELEASE||p1==SAVEPOINT_ROLLBACK );
  assert( db->pSavepoint || db->isTransactionSavepoint==0 );
  assert( checkSavepointCount(db) );

  if( p1==SAVEPOINT_BEGIN ){
    if( db->writeVdbeCnt>1 ){
      /* A new savepoint cannot be created if there are active write 
      ** statements (i.e. open read/write incremental blob handles).
      */
      sqlite3SetString(&p->zErrMsg, db, "cannot open savepoint - "
        "SQL statements in progress");
      rc = SQLITE_BUSY;
    }else{
................................................................................
        "cannot %s savepoint - SQL statements in progress",
        (p1==SAVEPOINT_ROLLBACK ? "rollback": "release")
      );
      rc = SQLITE_BUSY;
    }else{

      /* Determine whether or not this is a transaction savepoint. If so,
      ** operate on the currently open transaction. If this is a RELEASE 
      ** command, then the transaction is committed. If it is a ROLLBACK 
      ** command, then all changes made by the current transaction are 
      ** reverted, but the transaction is not actually closed.
      */
      int isTransaction = pSavepoint->pNext==0 && db->isTransactionSavepoint;
      if( isTransaction && p1==SAVEPOINT_RELEASE ){
        db->isTransactionSavepoint = 0;
        db->autoCommit = 1;
        if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
          p->pc = pc;
          db->autoCommit = 0;
          p->rc = rc = SQLITE_BUSY;
          goto vdbe_return;
        }


      }else{
        int ii;
        iSavepoint = db->nSavepoint - iSavepoint - 1;
        for(ii=0; ii<db->nDb; ii++){
          rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint);
          if( rc!=SQLITE_OK ){
            goto abort_due_to_error;







|







 







|







 







|
|
<
<



<







>
>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
....
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
....
2453
2454
2455
2456
2457
2458
2459
2460
2461


2462
2463
2464

2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.805 2008/12/18 18:31:39 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
** The following global variable is incremented every time a cursor
................................................................................
  */
  assert( db->pSavepoint==0 || db->autoCommit==0 );
  assert( p1==SAVEPOINT_BEGIN||p1==SAVEPOINT_RELEASE||p1==SAVEPOINT_ROLLBACK );
  assert( db->pSavepoint || db->isTransactionSavepoint==0 );
  assert( checkSavepointCount(db) );

  if( p1==SAVEPOINT_BEGIN ){
    if( db->writeVdbeCnt>0 ){
      /* A new savepoint cannot be created if there are active write 
      ** statements (i.e. open read/write incremental blob handles).
      */
      sqlite3SetString(&p->zErrMsg, db, "cannot open savepoint - "
        "SQL statements in progress");
      rc = SQLITE_BUSY;
    }else{
................................................................................
        "cannot %s savepoint - SQL statements in progress",
        (p1==SAVEPOINT_ROLLBACK ? "rollback": "release")
      );
      rc = SQLITE_BUSY;
    }else{

      /* Determine whether or not this is a transaction savepoint. If so,
      ** and this is a RELEASE command, then the current transaction 
      ** is committed. 


      */
      int isTransaction = pSavepoint->pNext==0 && db->isTransactionSavepoint;
      if( isTransaction && p1==SAVEPOINT_RELEASE ){

        db->autoCommit = 1;
        if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
          p->pc = pc;
          db->autoCommit = 0;
          p->rc = rc = SQLITE_BUSY;
          goto vdbe_return;
        }
        db->isTransactionSavepoint = 0;
        rc = p->rc;
      }else{
        int ii;
        iSavepoint = db->nSavepoint - iSavepoint - 1;
        for(ii=0; ii<db->nDb; ii++){
          rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint);
          if( rc!=SQLITE_OK ){
            goto abort_due_to_error;

Changes to test/savepoint.test.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
260
261
262
263
264
265
266
267

































































268
269
#
#    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: savepoint.test,v 1.1 2008/12/17 17:30:26 danielk1977 Exp $

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


#----------------------------------------------------------------------
# The following tests - savepoint-1.* - test that the SAVEPOINT, RELEASE
................................................................................
    INSERT INTO t3 VALUES('value');
  }
  execsql {SELECT * FROM t3}
} {value}
do_test savepoint-4.8 {
  execsql COMMIT
} {}


































































finish_test








|







 








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


5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
#
#    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: savepoint.test,v 1.2 2008/12/18 18:31:39 danielk1977 Exp $

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


#----------------------------------------------------------------------
# The following tests - savepoint-1.* - test that the SAVEPOINT, RELEASE
................................................................................
    INSERT INTO t3 VALUES('value');
  }
  execsql {SELECT * FROM t3}
} {value}
do_test savepoint-4.8 {
  execsql COMMIT
} {}

#------------------------------------------------------------------------
# Test some logic errors to do with the savepoint feature.
# 

do_test savepoint-5.1.1 {
  execsql {
    CREATE TABLE blobs(x);
    INSERT INTO blobs VALUES('a twentyeight character blob');
  }
  set fd [db incrblob blobs x 1]
  puts -nonewline $fd "hello"
  catchsql {SAVEPOINT abc}
} {1 {cannot open savepoint - SQL statements in progress}}
do_test savepoint-5.1.2 {
  close $fd
  catchsql {SAVEPOINT abc}
} {0 {}}

do_test savepoint-5.2 {
  execsql  {RELEASE abc}
  catchsql {RELEASE abc}
} {1 {no such savepoint: abc}}

do_test savepoint-5.3.1 {
  execsql  {SAVEPOINT abc}
  catchsql {ROLLBACK TO def}
} {1 {no such savepoint: def}}
do_test savepoint-5.3.2 {
  execsql  {SAVEPOINT def}
  set fd [db incrblob -readonly blobs x 1]
  catchsql {ROLLBACK TO def}
} {1 {cannot rollback savepoint - SQL statements in progress}}
do_test savepoint-5.3.3 {
  catchsql  {RELEASE def}
} {0 {}}
do_test savepoint-5.3.4 {
  close $fd
  execsql  {savepoint def}
  set fd [db incrblob blobs x 1]
  catchsql {release def}
} {1 {cannot release savepoint - SQL statements in progress}}
do_test savepoint-5.3.5 {
  close $fd
  execsql {release abc}
} {}

do_test savepoint-5.4.1 {
  execsql {
    SAVEPOINT main;
    INSERT INTO blobs VALUES('another blob');
  }
} {}
do_test savepoint-5.4.2 {
  sqlite3 db2 test.db
  execsql { BEGIN ; SELECT * FROM blobs } db2
  catchsql { RELEASE main }
} {1 {database is locked}}
do_test savepoint-5.4.3 {
  db2 close
  catchsql { RELEASE main }
} {0 {}}
do_test savepoint-5.4.4 {
  execsql { SELECT x FROM blobs WHERE rowid = 2 }
} {{another blob}}

finish_test

Changes to test/savepoint2.test.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#
#    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: savepoint2.test,v 1.1 2008/12/18 15:45:07 danielk1977 Exp $

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

# Tests in this file are quite similar to those run by trans.test and
# avtrans.test.
#

proc signature {} {
  return [db eval {SELECT count(*), md5sum(x) FROM t3}]
}



do_test savepoint2-1 {
  execsql {
    PRAGMA cache_size=10;
  }
  db close
  sqlite3 db test.db
  execsql {
    BEGIN;
    CREATE TABLE t3(x TEXT);
    INSERT INTO t3 VALUES(randstr(10,400));
    INSERT INTO t3 VALUES(randstr(10,400));
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;







|












<
<



<
<
<
<







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24


25
26
27




28
29
30
31
32
33
34
#
#    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: savepoint2.test,v 1.2 2008/12/18 18:31:39 danielk1977 Exp $

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

# Tests in this file are quite similar to those run by trans.test and
# avtrans.test.
#

proc signature {} {
  return [db eval {SELECT count(*), md5sum(x) FROM t3}]
}



do_test savepoint2-1 {
  execsql {
    PRAGMA cache_size=10;




    BEGIN;
    CREATE TABLE t3(x TEXT);
    INSERT INTO t3 VALUES(randstr(10,400));
    INSERT INTO t3 VALUES(randstr(10,400));
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;
    INSERT INTO t3 SELECT randstr(10,400) FROM t3;

Added test/savepoint3.test.































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# 2008 December 15
#
# The author disclaims copyright to this source code.  In place of
# 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: savepoint3.test,v 1.1 2008/12/18 18:31:39 danielk1977 Exp $

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

source $testdir/malloc_common.tcl

do_malloc_test savepoint3-1 -sqlprep {
  CREATE TABLE t1(a, b, c);
  INSERT INTO t1 VALUES(1, 2, 3);
} -sqlbody {
  SAVEPOINT one;
    INSERT INTO t1 VALUES(4, 5, 6);
    SAVEPOINT two;
      DELETE FROM t1;
    ROLLBACK TO two;
  RELEASE one;
}

do_malloc_test savepoint3-1 -sqlprep {
  PRAGMA cache_size = 10;
  CREATE TABLE t1(a, b, c);
  INSERT INTO t1 VALUES(randstr(400,400), randstr(400,400), randstr(400,400));
  INSERT INTO t1 SELECT 
    randstr(400,400), randstr(400,400), randstr(400,400) FROM t1;
  INSERT INTO t1 
    SELECT randstr(400,400), randstr(400,400), randstr(400,400) FROM t1;
  INSERT INTO t1 
    SELECT randstr(400,400), randstr(400,400), randstr(400,400) FROM t1;
  INSERT INTO t1 
    SELECT randstr(400,400), randstr(400,400), randstr(400,400) FROM t1;
  INSERT INTO t1 
    SELECT randstr(400,400), randstr(400,400), randstr(400,400) FROM t1;
  INSERT INTO t1 
    SELECT randstr(400,400), randstr(400,400), randstr(400,400) FROM t1;
  INSERT INTO t1 
    SELECT randstr(400,400), randstr(400,400), randstr(400,400) FROM t1;
  INSERT INTO t1 
    SELECT randstr(400,400), randstr(400,400), randstr(400,400) FROM t1;
} -sqlbody {
  PRAGMA cache_size = 10;
  SAVEPOINT one;
    DELETE FROM t1 WHERE rowid < 5;
    SAVEPOINT two;
      DELETE FROM t1 WHERE rowid > 10;
    ROLLBACK TO two;
  ROLLBACK TO one;
  RELEASE one;
}

finish_test