SQLite

Check-in [d256c14943]
Login

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

Overview
Comment:Add some tests for overlapping SELECT, COMMIT and ROLLBACK commands. (CVS 1774)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: d256c14943968e7adf4b73988cac6af941c9b12d
User & Date: danielk1977 2004-06-30 06:30:26.000
Context
2004-06-30
08:20
Fixes for compiler warnings. Also more coverage. (CVS 1775) (check-in: fa19c77bf0 user: danielk1977 tags: trunk)
06:30
Add some tests for overlapping SELECT, COMMIT and ROLLBACK commands. (CVS 1774) (check-in: d256c14943 user: danielk1977 tags: trunk)
04:02
Improve test coverage of util.c (CVS 1773) (check-in: 68ac322137 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/vacuum.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** This file contains code used to implement the VACUUM command.
**
** Most of the code in this file may be omitted by defining the
** SQLITE_OMIT_VACUUM macro.
**
** $Id: vacuum.c,v 1.24 2004/06/26 08:38:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"

#if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
/*
** Generate a random name of 20 character in length.







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** This file contains code used to implement the VACUUM command.
**
** Most of the code in this file may be omitted by defining the
** SQLITE_OMIT_VACUUM macro.
**
** $Id: vacuum.c,v 1.25 2004/06/30 06:30:26 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"

#if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
/*
** Generate a random name of 20 character in length.
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
  int rc = SQLITE_OK;     /* Return code from service routines */
#if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
  const char *zFilename;  /* full pathname of the database file */
  int nFilename;          /* number of characters  in zFilename[] */
  char *zTemp = 0;        /* a temporary file in same directory as zFilename */
  int i;                  /* Loop counter */
  Btree *pTemp;

  char *zSql = 0;
  sqlite3_stmt *pStmt = 0;

  if( !db->autoCommit ){
    sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction", 
       (char*)0);
    rc = SQLITE_ERROR;
    goto end_of_vacuum;
  }







<

<







93
94
95
96
97
98
99

100

101
102
103
104
105
106
107
  int rc = SQLITE_OK;     /* Return code from service routines */
#if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
  const char *zFilename;  /* full pathname of the database file */
  int nFilename;          /* number of characters  in zFilename[] */
  char *zTemp = 0;        /* a temporary file in same directory as zFilename */
  int i;                  /* Loop counter */
  Btree *pTemp;

  char *zSql = 0;


  if( !db->autoCommit ){
    sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction", 
       (char*)0);
    rc = SQLITE_ERROR;
    goto end_of_vacuum;
  }
125
126
127
128
129
130
131
132







133

134
135
136
137
138
139
140
  strcpy(zTemp, zFilename);
  for(i=0; i<10; i++){
    zTemp[nFilename] = '-';
    randomName((unsigned char*)&zTemp[nFilename+1]);
    if( !sqlite3OsFileExists(zTemp) ) break;
  }

  /* Attach the temporary database as 'vacuum' */







  zSql = sqlite3MPrintf("ATTACH '%s' AS vacuum_db;", zTemp);

  if( !zSql ){
    rc = SQLITE_NOMEM;
    goto end_of_vacuum;
  }
  rc = execSql(db, zSql);
  sqliteFree(zSql);
  zSql = 0;







|
>
>
>
>
>
>
>

>







123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
  strcpy(zTemp, zFilename);
  for(i=0; i<10; i++){
    zTemp[nFilename] = '-';
    randomName((unsigned char*)&zTemp[nFilename+1]);
    if( !sqlite3OsFileExists(zTemp) ) break;
  }

  /* Attach the temporary database as 'vacuum_db'. The synchronous pragma
  ** can be set to 'off' for this file, as it is not recovered if a crash
  ** occurs anyway. The integrity of the database is maintained by a
  ** (possibly synchronous) transaction opened on the main database before
  ** sqlite3BtreeCopyFile() is called.
  **
  ** An optimisation would be to use a non-journaled pager.
  */
  zSql = sqlite3MPrintf("ATTACH '%s' AS vacuum_db;", zTemp);
  execSql(db, "PRAGMA vacuum_db.synchronous = off;");
  if( !zSql ){
    rc = SQLITE_NOMEM;
    goto end_of_vacuum;
  }
  rc = execSql(db, zSql);
  sqliteFree(zSql);
  zSql = 0;
213
214
215
216
217
218
219
220







221
222
223
224
225
226
227
228
229
230

    rc = sqlite3BtreeCopyFile(pMain, pTemp);
    if( rc!=SQLITE_OK ) goto end_of_vacuum;
    rc = sqlite3BtreeCommit(pMain);
  }

end_of_vacuum:
  execSql(db, "ROLLBACK;");







  execSql(db, "DETACH vacuum_db;");
  if( zTemp ){
    sqlite3OsDelete(zTemp);
    sqliteFree(zTemp);
  }
  if( zSql ) sqliteFree( zSql );
  if( pStmt ) sqlite3_finalize( pStmt );
#endif
  return rc;
} 







|
>
>
>
>
>
>
>






<



219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239

240
241
242

    rc = sqlite3BtreeCopyFile(pMain, pTemp);
    if( rc!=SQLITE_OK ) goto end_of_vacuum;
    rc = sqlite3BtreeCommit(pMain);
  }

end_of_vacuum:
  /* Currently there is an SQL level transaction open on the vacuum
  ** database. No locks are held on any other files (since the main file
  ** was committed at the btree level). So it safe to end the transaction
  ** by manually setting the autoCommit flag to true and detaching the
  ** vacuum database. The vacuum_db journal file is deleted when the pager
  ** is closed by the DETACH.
  */
  db->autoCommit = 1;
  execSql(db, "DETACH vacuum_db;");
  if( zTemp ){
    sqlite3OsDelete(zTemp);
    sqliteFree(zTemp);
  }
  if( zSql ) sqliteFree( zSql );

#endif
  return rc;
} 
Changes to src/vdbe.c.
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
**
** 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.396 2004/06/30 02:43:38 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*







|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
**
** 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.397 2004/06/30 06:30:26 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
2208
2209
2210
2211
2212
2213
2214
2215

2216
2217
2218
2219
2220
2221
2222
2223










2224
2225
2226
2227
2228
2229
2230
2231
  }
  break;
}

/* Opcode: AutoCommit P1 P2 *
**
** Set the database auto-commit flag to P1 (1 or 0). If P2 is true, roll
** back any currently active btree transactions.

*/
case OP_AutoCommit: {
  u8 i = pOp->p1;
  u8 rollback = pOp->p2;

  assert( i==1 || i==0 );
  assert( i==1 || rollback==0 );











  if( i!=db->autoCommit ){
    db->autoCommit = i;
    p->autoCommitOn |= i;
    if( pOp->p2 ){
      sqlite3RollbackAll(db);
    }
  }else{
    sqlite3SetString(&p->zErrMsg,







|
>








>
>
>
>
>
>
>
>
>
>
|







2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
  }
  break;
}

/* Opcode: AutoCommit P1 P2 *
**
** Set the database auto-commit flag to P1 (1 or 0). If P2 is true, roll
** back any currently active btree transactions. If there are any active
** VMs (apart from this one), then the COMMIT or ROLLBACK statement fails.
*/
case OP_AutoCommit: {
  u8 i = pOp->p1;
  u8 rollback = pOp->p2;

  assert( i==1 || i==0 );
  assert( i==1 || rollback==0 );

  assert( db->activeVdbeCnt>0 );

  if( db->activeVdbeCnt>1 && i && !db->autoCommit ){
    /* If this instruction implements a COMMIT or ROLLBACK, other VMs are
    ** still running, and a transaction is active, return an error indicating
    ** that the other VMs must complete first. 
    */
    sqlite3SetString(&p->zErrMsg, "cannot ", rollback?"rollback":"commit", 
        " transaction - SQL statements in progress", 0);
    rc = SQLITE_ERROR;
  }else if( i!=db->autoCommit ){
    db->autoCommit = i;
    p->autoCommitOn |= i;
    if( pOp->p2 ){
      sqlite3RollbackAll(db);
    }
  }else{
    sqlite3SetString(&p->zErrMsg,
Changes to test/capi2.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2003 January 29
#
# 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.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script testing the callback-free C/C++ API.
#
# $Id: capi2.test,v 1.17 2004/06/26 09:50:12 danielk1977 Exp $
#

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

# Return the text values from the current row pointed at by STMT as a list.
proc get_row_values {STMT} {













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2003 January 29
#
# 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.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script testing the callback-free C/C++ API.
#
# $Id: capi2.test,v 1.18 2004/06/30 06:30:26 danielk1977 Exp $
#

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

# Return the text values from the current row pointed at by STMT as a list.
proc get_row_values {STMT} {
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
} {1 3 3}
do_test capi2-6.20 {
  list [sqlite3_step $VM1] \
       [sqlite3_column_count $VM1] \
       [get_row_values $VM1] \
       [get_column_names $VM1]
} {SQLITE_ROW 1 9 {x counter}}
do_test capi2-6.21 {
  execsql {ROLLBACK; SELECT * FROM t1}
} {1 2 3}
do_test capi2-6.22 {
  list [sqlite3_step $VM1] \
       [sqlite3_column_count $VM1] \
       [get_row_values $VM1] \
       [get_column_names $VM1]
} {SQLITE_ROW 1 10 {x counter}}
do_test capi2-6.23 {
  execsql {BEGIN TRANSACTION;}
} {}
do_test capi2-6.24 {
  list [sqlite3_step $VM1] \
       [sqlite3_column_count $VM1] \
       [get_row_values $VM1] \
       [get_column_names $VM1]
} {SQLITE_ROW 1 11 {x counter}}
do_test capi2-6.25 {
  execsql {
    INSERT INTO t1 VALUES(2,3,4);
    SELECT * FROM t1;
  }
} {1 2 3 2 3 4}
do_test capi2-6.26 {
  list [sqlite3_step $VM1] \
       [sqlite3_column_count $VM1] \
       [get_row_values $VM1] \
       [get_column_names $VM1]
} {SQLITE_ROW 1 12 {x counter}}
do_test capi2-6.27 {







|
|
|






|
|
|











|







480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
} {1 3 3}
do_test capi2-6.20 {
  list [sqlite3_step $VM1] \
       [sqlite3_column_count $VM1] \
       [get_row_values $VM1] \
       [get_column_names $VM1]
} {SQLITE_ROW 1 9 {x counter}}
#do_test capi2-6.21 {
#  execsql {ROLLBACK; SELECT * FROM t1}
#} {1 2 3}
do_test capi2-6.22 {
  list [sqlite3_step $VM1] \
       [sqlite3_column_count $VM1] \
       [get_row_values $VM1] \
       [get_column_names $VM1]
} {SQLITE_ROW 1 10 {x counter}}
#do_test capi2-6.23 {
#  execsql {BEGIN TRANSACTION;}
#} {}
do_test capi2-6.24 {
  list [sqlite3_step $VM1] \
       [sqlite3_column_count $VM1] \
       [get_row_values $VM1] \
       [get_column_names $VM1]
} {SQLITE_ROW 1 11 {x counter}}
do_test capi2-6.25 {
  execsql {
    INSERT INTO t1 VALUES(2,3,4);
    SELECT * FROM t1;
  }
} {1 3 3 2 3 4}
do_test capi2-6.26 {
  list [sqlite3_step $VM1] \
       [sqlite3_column_count $VM1] \
       [get_row_values $VM1] \
       [get_column_names $VM1]
} {SQLITE_ROW 1 12 {x counter}}
do_test capi2-6.27 {
Changes to test/capi3.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2003 January 29
#
# 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.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script testing the callback-free C/C++ API.
#
# $Id: capi3.test,v 1.18 2004/06/30 02:35:51 danielk1977 Exp $
#

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

# Return the UTF-16 representation of the supplied UTF-8 string $str.
# If $nt is true, append two 0x00 bytes as a nul terminator.













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2003 January 29
#
# 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.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script testing the callback-free C/C++ API.
#
# $Id: capi3.test,v 1.19 2004/06/30 06:30:26 danielk1977 Exp $
#

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

# Return the UTF-16 representation of the supplied UTF-8 string $str.
# If $nt is true, append two 0x00 bytes as a nul terminator.
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
do_test capi3-8.2 {
  set ::bt [btree_open test.db 10 0]
  btree_begin_transaction $::bt
  set ::bc [btree_cursor $::bt 1 1]

  # Build a 5-field row record consisting of 5 null records. This is
  # officially black magic.
  unset data
  set data [binary format c6 {6 0 0 0 0 0}]
  btree_insert $::bc 5 $data

  btree_close_cursor $::bc
  btree_commit $::bt
  btree_close $::bt
} {}







|







494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
do_test capi3-8.2 {
  set ::bt [btree_open test.db 10 0]
  btree_begin_transaction $::bt
  set ::bc [btree_cursor $::bt 1 1]

  # Build a 5-field row record consisting of 5 null records. This is
  # officially black magic.
  catch {unset data}
  set data [binary format c6 {6 0 0 0 0 0}]
  btree_insert $::bc 5 $data

  btree_close_cursor $::bc
  btree_commit $::bt
  btree_close $::bt
} {}
597
598
599
600
601
602
603





604





605








606










607

































































































































do_test capi3-10-3 {
  utf8 [sqlite3_errmsg16 $::DB]
} {out of memory}
db close
sqlite_malloc_fail 0
}






finish_test


































































































































































>
>
>
>
>
|
>
>
>
>
>
|
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
do_test capi3-10-3 {
  utf8 [sqlite3_errmsg16 $::DB]
} {out of memory}
db close
sqlite_malloc_fail 0
}

# The following tests - capi3-11.* - test that a COMMIT or ROLLBACK
# statement issued while there are still outstanding VMs that are part of
# the transaction fails.
set DB [sqlite3 db test.db]
sqlite_register_test_function $DB func
do_test capi3-11.1 {
  execsql {
    BEGIN;
    CREATE TABLE t1(a, b);
    INSERT INTO t1 VALUES(1, 'int');
    INSERT INTO t1 VALUES(2, 'notatype');
  }
} {}
do_test capi3-11.2 {
  set STMT [sqlite3_prepare $DB "SELECT func(b, a) FROM t1" -1 TAIL]
  sqlite3_step $STMT
} {SQLITE_ROW}
do_test capi3-11.3 {
  catchsql {
    COMMIT;
  }
} {1 {cannot commit transaction - SQL statements in progress}}
do_test capi3-11.4 {
  sqlite3_step $STMT
} {SQLITE_ERROR}
do_test capi3-11.5 {
  sqlite3_finalize $STMT
} {SQLITE_ERROR}
do_test capi3-11.6 {
  catchsql {
    SELECT * FROM t1;
  }
} {0 {1 int 2 notatype}}
do_test capi3-11.7 {
  catchsql {
    COMMIT;
  }
} {0 {}}
do_test capi3-11.8 {
  execsql {
    CREATE TABLE t2(a);
    INSERT INTO t2 VALUES(1);
    INSERT INTO t2 VALUES(2);
    BEGIN;
    INSERT INTO t2 VALUES(3);
  }
} {}
do_test capi3-11.9 {
  set STMT [sqlite3_prepare $DB "SELECT a FROM t2" -1 TAIL]
  sqlite3_step $STMT
} {SQLITE_ROW}
do_test capi3-11.3 {
  catchsql {
    ROLLBACK;
  }
} {1 {cannot rollback transaction - SQL statements in progress}}
do_test capi3-11.10 {
  sqlite3_step $STMT
} {SQLITE_ROW}
do_test capi3-11.11 {
  sqlite3_step $STMT
} {SQLITE_ROW}
do_test capi3-11.12 {
  sqlite3_step $STMT
} {SQLITE_DONE}
do_test capi3-11.13 {
  sqlite3_finalize $STMT
} {SQLITE_OK}
do_test capi3-11.14 {
  execsql {
    SELECT a FROM t2;
  }
} {1 2 3}
do_test capi3-11.15 {
  catchsql {
    ROLLBACK;
  }
} {0 {}}
do_test capi3-11.16 {
  execsql {
    SELECT a FROM t2;
  }
} {1 2}

# Sanity check on the definition of 'outstanding VM'. This means any VM
# that has had sqlite3_step() called more recently than sqlite3_finalize() or
# sqlite3_reset(). So a VM that has just been prepared or reset does not
# count as an active VM.
do_test capi3-11.17 {
  execsql {
    BEGIN;
  }
} {}
do_test capi3-11.18 {
  set STMT [sqlite3_prepare $DB "SELECT a FROM t1" -1 TAIL]
  catchsql {
    COMMIT;
  }
} {0 {}}
do_test capi3-11.19 {
  sqlite3_step $STMT
} {SQLITE_ROW}
do_test capi3-11.20 {
  catchsql {
    BEGIN;
    COMMIT;
  }
} {1 {cannot commit transaction - SQL statements in progress}}
do_test capi3-11.20 {
  sqlite3_reset $STMT
  catchsql {
    COMMIT;
  }
} {0 {}}
do_test capi3-11.21 {
  sqlite3_finalize $STMT
} {SQLITE_OK}

# The following tests - capi3-12.* - check that it's Ok to start a
# transaction while other VMs are active, and that it's Ok to execute
# atomic updates in the same situation (so long as they are on a different
# table).
do_test capi3-12.1 {
  set STMT [sqlite3_prepare $DB "SELECT a FROM t2" -1 TAIL]
  sqlite3_step $STMT
} {SQLITE_ROW}
do_test capi3-12.2 {
  catchsql {
    INSERT INTO t1 VALUES(3, NULL);
  }
} {0 {}}
do_test capi3-12.3 {
  catchsql {
    INSERT INTO t2 VALUES(4);
  }
} {1 {database table is locked}}
do_test capi3-12.4 {
  catchsql {
    BEGIN;
    INSERT INTO t1 VALUES(4, NULL);
  }
} {0 {}}
do_test capi3-12.5 {
  sqlite3_step $STMT
} {SQLITE_ROW}
do_test capi3-12.6 {
  sqlite3_step $STMT
} {SQLITE_DONE}
do_test capi3-12.7 {
  sqlite3_finalize $STMT
} {SQLITE_OK}
do_test capi3-12.8 {
  execsql {
    COMMIT;
    SELECT a FROM t1;
  }
} {1 2 3 4}


finish_test