/ Check-in [df51cb16]
Login

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

Overview
Comment:Fix for ticket #110: return an error if trying to start a transaction within a transaction or when attempting to commit or rollback outside of a transaction. (CVS 721)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: df51cb166bf7c5b8b0530cc86df8d2d68de81a40
User & Date: drh 2002-08-18 20:28:07
Context
2002-08-18
22:41
This COLLATE keyword was not being parsed correctly inside CREATE TABLE statements - it was being included as part of the datatype. This fixes the problem. (CVS 722) check-in: 39bd52d3 user: drh tags: trunk
20:28
Fix for ticket #110: return an error if trying to start a transaction within a transaction or when attempting to commit or rollback outside of a transaction. (CVS 721) check-in: df51cb16 user: drh tags: trunk
19:09
Documentation updates. (CVS 720) check-in: e372a60b user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/build.c.

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
....
1725
1726
1727
1728
1729
1730
1731
1732





1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746





1747
1748
1749
1750
1751
1752
1753
....
1754
1755
1756
1757
1758
1759
1760
1761





1762
1763
1764
1765
1766
1767
1768
**     COPY
**     VACUUM
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.108 2002/08/15 01:26:09 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Check to see if the schema for the database needs
................................................................................
** Begin a transaction
*/
void sqliteBeginTransaction(Parse *pParse, int onError){
  sqlite *db;

  if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
  if( pParse->nErr || sqlite_malloc_failed ) return;
  if( db->flags & SQLITE_InTrans ) return;





  sqliteBeginWriteOperation(pParse, 0);
  db->flags |= SQLITE_InTrans;
  db->onError = onError;
}

/*
** Commit a transaction
*/
void sqliteCommitTransaction(Parse *pParse){
  sqlite *db;

  if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
  if( pParse->nErr || sqlite_malloc_failed ) return;
  if( (db->flags & SQLITE_InTrans)==0 ) return;





  db->flags &= ~SQLITE_InTrans;
  sqliteEndWriteOperation(pParse);
  db->onError = OE_Default;
}

/*
** Rollback a transaction
................................................................................
*/
void sqliteRollbackTransaction(Parse *pParse){
  sqlite *db;
  Vdbe *v;

  if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
  if( pParse->nErr || sqlite_malloc_failed ) return;
  if( (db->flags & SQLITE_InTrans)==0 ) return;





  v = sqliteGetVdbe(pParse);
  if( v ){
    sqliteVdbeAddOp(v, OP_Rollback, 0, 0);
  }
  db->flags &= ~SQLITE_InTrans;
  db->onError = OE_Default;
}







|







 







|
>
>
>
>
>













|
>
>
>
>
>







 







|
>
>
>
>
>







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
....
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
....
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
**     COPY
**     VACUUM
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.109 2002/08/18 20:28:07 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Check to see if the schema for the database needs
................................................................................
** Begin a transaction
*/
void sqliteBeginTransaction(Parse *pParse, int onError){
  sqlite *db;

  if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
  if( pParse->nErr || sqlite_malloc_failed ) return;
  if( db->flags & SQLITE_InTrans ){
    pParse->nErr++;
    sqliteSetString(&pParse->zErrMsg, "cannot start a transaction "
       "within a transaction", 0);
    return;
  }
  sqliteBeginWriteOperation(pParse, 0);
  db->flags |= SQLITE_InTrans;
  db->onError = onError;
}

/*
** Commit a transaction
*/
void sqliteCommitTransaction(Parse *pParse){
  sqlite *db;

  if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
  if( pParse->nErr || sqlite_malloc_failed ) return;
  if( (db->flags & SQLITE_InTrans)==0 ){
    pParse->nErr++;
    sqliteSetString(&pParse->zErrMsg, 
       "cannot commit - no transaction is active", 0);
    return;
  }
  db->flags &= ~SQLITE_InTrans;
  sqliteEndWriteOperation(pParse);
  db->onError = OE_Default;
}

/*
** Rollback a transaction
................................................................................
*/
void sqliteRollbackTransaction(Parse *pParse){
  sqlite *db;
  Vdbe *v;

  if( pParse==0 || (db=pParse->db)==0 || db->pBe==0 ) return;
  if( pParse->nErr || sqlite_malloc_failed ) return;
  if( (db->flags & SQLITE_InTrans)==0 ){
    pParse->nErr++;
    sqliteSetString(&pParse->zErrMsg,
       "cannot rollback - no transaction is active", 0);
    return; 
  }
  v = sqliteGetVdbe(pParse);
  if( v ){
    sqliteVdbeAddOp(v, OP_Rollback, 0, 0);
  }
  db->flags &= ~SQLITE_InTrans;
  db->onError = OE_Default;
}

Changes to test/conflict.test.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
..
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
...
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
...
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
...
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
...
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
...
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
...
652
653
654
655
656
657
658
659
660
661
662
663
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for the conflict resolution extension
# to SQLite.
#
# $Id: conflict.test,v 1.13 2002/06/28 12:18:48 drh Exp $

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

# Create tables for the first group of tests.
#
do_test conflict-1.0 {
................................................................................
      DELETE FROM t1;
      DELETE FROM t2;
      INSERT INTO t1 VALUES(1,2,3);
      BEGIN $conf;
      INSERT INTO t2 VALUES(1); 
      $cmd INTO t1 VALUES(1,2,4);
    }]} r1]
    execsql {COMMIT}
    if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]}
    set r2 [execsql {SELECT x FROM t2}]
    list $r0 $r1 $r2
  } [list $t0 $t1 $t2]
}

# Create tables for the first group of tests.
................................................................................
      DELETE FROM t1;
      DELETE FROM t2;
      INSERT INTO t1 VALUES(1,2,3);
      BEGIN $conf;
      INSERT INTO t2 VALUES(1); 
      $cmd INTO t1 VALUES(1,2,4);
    }]} r1]
    execsql {COMMIT}
    if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]}
    set r2 [execsql {SELECT x FROM t2}]
    list $r0 $r1 $r2
  } [list $t0 $t1 $t2]
}

# Create tables for the first group of tests.
................................................................................
      DELETE FROM t1;
      DELETE FROM t2;
      INSERT INTO t1 VALUES(1,2,3);
      BEGIN $conf;
      INSERT INTO t2 VALUES(1); 
      $cmd INTO t1 VALUES(1,2,4);
    }]} r1]
    execsql {COMMIT}
    if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]}
    set r2 [execsql {SELECT x FROM t2}]
    list $r0 $r1 $r2
  } [list $t0 $t1 $t2]
}

do_test conflict-4.0 {
................................................................................
      CREATE TABLE t1(a,b,c,UNIQUE(a,b) $conf1);
      DELETE FROM t2;
      INSERT INTO t1 VALUES(1,2,3);
      BEGIN $conf2;
      INSERT INTO t2 VALUES(1); 
      $cmd INTO t1 VALUES(1,2,4);
    }]} r1]
    execsql {COMMIT}
    if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]}
    set r2 [execsql {SELECT x FROM t2}]
    list $r0 $r1 $r2
  } [list $t0 $t1 $t2]
}

do_test conflict-5.0 {
................................................................................
      DROP TABLE t1;
      CREATE TABLE t1(a,b,c NOT NULL $conf1 DEFAULT 5);
      DELETE FROM t2;
      BEGIN $conf2;
      INSERT INTO t2 VALUES(1); 
      $cmd INTO t1 VALUES(1,2,NULL);
    }]} r1]
    execsql {COMMIT}
    if {!$r0} {set r1 [execsql {SELECT c FROM t1}]}
    set r2 [execsql {SELECT x FROM t2}]
    list $r0 $r1 $r2
  } [list $t0 $t1 $t2]
}

do_test conflict-6.0 {
................................................................................
      INSERT INTO t1 SELECT * FROM t2;
      UPDATE t3 SET x=0;
      BEGIN $conf2;
      $cmd t3 SET x=1;
      $cmd t1 SET b=b*2;
      $cmd t1 SET a=c+5;
    }]} r1]
    execsql {COMMIT}
    if {!$r0} {set r1 [execsql {SELECT a FROM t1 ORDER BY b}]}
    set r2 [execsql {SELECT x FROM t3}]
    list $r0 $r1 $r2
  } [list $t0 $t1 $t2]
}

# Test to make sure a lot of IGNOREs don't cause a stack overflow
................................................................................
    BEGIN;
    UPDATE t3 SET x=x+1;
    INSERT INTO t2 VALUES(3,3,3,3,1);
    SELECT * FROM t2;
  }
} {1 {constraint failed}}
do_test conflict-9.20 {
  execsql {COMMIT}
  execsql {SELECT * FROM t3}
} {5}
do_test conflict-9.21 {
  catchsql {
    BEGIN;
    UPDATE t3 SET x=x+1;
    UPDATE t2 SET e=e+1 WHERE e=1;
    SELECT * FROM t2;
  }
} {1 {constraint failed}}
do_test conflict-9.22 {
  execsql {COMMIT}
  execsql {SELECT * FROM t3}
} {5}
do_test conflict-9.23 {
  catchsql {
    INSERT INTO t2 VALUES(3,3,1,3,3);
    SELECT * FROM t2;
  }
................................................................................
    BEGIN;
    UPDATE t3 SET x=x+1;
    INSERT INTO t2 VALUES(3,3,1,3,3);
    SELECT * FROM t2;
  }
} {0 {3 3 1 3 3}}
do_test conflict-9.26 {
  execsql {COMMIT}
  execsql {SELECT * FROM t3}
} {6}

finish_test







|







 







|







 







|







 







|







 







|







 







|







 







|







 







|











|







 







|




9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
..
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
...
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
...
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
...
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
...
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
...
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
...
652
653
654
655
656
657
658
659
660
661
662
663
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for the conflict resolution extension
# to SQLite.
#
# $Id: conflict.test,v 1.14 2002/08/18 20:28:07 drh Exp $

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

# Create tables for the first group of tests.
#
do_test conflict-1.0 {
................................................................................
      DELETE FROM t1;
      DELETE FROM t2;
      INSERT INTO t1 VALUES(1,2,3);
      BEGIN $conf;
      INSERT INTO t2 VALUES(1); 
      $cmd INTO t1 VALUES(1,2,4);
    }]} r1]
    catch {execsql {COMMIT}}
    if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]}
    set r2 [execsql {SELECT x FROM t2}]
    list $r0 $r1 $r2
  } [list $t0 $t1 $t2]
}

# Create tables for the first group of tests.
................................................................................
      DELETE FROM t1;
      DELETE FROM t2;
      INSERT INTO t1 VALUES(1,2,3);
      BEGIN $conf;
      INSERT INTO t2 VALUES(1); 
      $cmd INTO t1 VALUES(1,2,4);
    }]} r1]
    catch {execsql {COMMIT}}
    if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]}
    set r2 [execsql {SELECT x FROM t2}]
    list $r0 $r1 $r2
  } [list $t0 $t1 $t2]
}

# Create tables for the first group of tests.
................................................................................
      DELETE FROM t1;
      DELETE FROM t2;
      INSERT INTO t1 VALUES(1,2,3);
      BEGIN $conf;
      INSERT INTO t2 VALUES(1); 
      $cmd INTO t1 VALUES(1,2,4);
    }]} r1]
    catch {execsql {COMMIT}}
    if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]}
    set r2 [execsql {SELECT x FROM t2}]
    list $r0 $r1 $r2
  } [list $t0 $t1 $t2]
}

do_test conflict-4.0 {
................................................................................
      CREATE TABLE t1(a,b,c,UNIQUE(a,b) $conf1);
      DELETE FROM t2;
      INSERT INTO t1 VALUES(1,2,3);
      BEGIN $conf2;
      INSERT INTO t2 VALUES(1); 
      $cmd INTO t1 VALUES(1,2,4);
    }]} r1]
    catch {execsql {COMMIT}}
    if {$r0} {set r1 {}} {set r1 [execsql {SELECT c FROM t1}]}
    set r2 [execsql {SELECT x FROM t2}]
    list $r0 $r1 $r2
  } [list $t0 $t1 $t2]
}

do_test conflict-5.0 {
................................................................................
      DROP TABLE t1;
      CREATE TABLE t1(a,b,c NOT NULL $conf1 DEFAULT 5);
      DELETE FROM t2;
      BEGIN $conf2;
      INSERT INTO t2 VALUES(1); 
      $cmd INTO t1 VALUES(1,2,NULL);
    }]} r1]
    catch {execsql {COMMIT}}
    if {!$r0} {set r1 [execsql {SELECT c FROM t1}]}
    set r2 [execsql {SELECT x FROM t2}]
    list $r0 $r1 $r2
  } [list $t0 $t1 $t2]
}

do_test conflict-6.0 {
................................................................................
      INSERT INTO t1 SELECT * FROM t2;
      UPDATE t3 SET x=0;
      BEGIN $conf2;
      $cmd t3 SET x=1;
      $cmd t1 SET b=b*2;
      $cmd t1 SET a=c+5;
    }]} r1]
    catch {execsql {COMMIT}}
    if {!$r0} {set r1 [execsql {SELECT a FROM t1 ORDER BY b}]}
    set r2 [execsql {SELECT x FROM t3}]
    list $r0 $r1 $r2
  } [list $t0 $t1 $t2]
}

# Test to make sure a lot of IGNOREs don't cause a stack overflow
................................................................................
    BEGIN;
    UPDATE t3 SET x=x+1;
    INSERT INTO t2 VALUES(3,3,3,3,1);
    SELECT * FROM t2;
  }
} {1 {constraint failed}}
do_test conflict-9.20 {
  catch {execsql {COMMIT}}
  execsql {SELECT * FROM t3}
} {5}
do_test conflict-9.21 {
  catchsql {
    BEGIN;
    UPDATE t3 SET x=x+1;
    UPDATE t2 SET e=e+1 WHERE e=1;
    SELECT * FROM t2;
  }
} {1 {constraint failed}}
do_test conflict-9.22 {
  catch {execsql {COMMIT}}
  execsql {SELECT * FROM t3}
} {5}
do_test conflict-9.23 {
  catchsql {
    INSERT INTO t2 VALUES(3,3,1,3,3);
    SELECT * FROM t2;
  }
................................................................................
    BEGIN;
    UPDATE t3 SET x=x+1;
    INSERT INTO t2 VALUES(3,3,1,3,3);
    SELECT * FROM t2;
  }
} {0 {3 3 1 3 3}}
do_test conflict-9.26 {
  catch {execsql {COMMIT}}
  execsql {SELECT * FROM t3}
} {6}

finish_test

Changes to test/lock.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
#    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 is database locks.
#
# $Id: lock.test,v 1.15 2002/06/25 13:16:04 drh Exp $


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

# Create an alternative connection to the database
#
................................................................................
# Try to start two transactions in a row
#
do_test lock-3.1 {
  execsql {BEGIN TRANSACTION}
  set r [catch {execsql {BEGIN TRANSACTION}} msg]
  execsql {ROLLBACK}
  lappend r $msg
} {0 {}}
integrity_check lock-3.2

do_test lock-999.1 {
  rename db2 {}
} {}

finish_test







|







 







|







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
#    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 is database locks.
#
# $Id: lock.test,v 1.16 2002/08/18 20:28:07 drh Exp $


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

# Create an alternative connection to the database
#
................................................................................
# Try to start two transactions in a row
#
do_test lock-3.1 {
  execsql {BEGIN TRANSACTION}
  set r [catch {execsql {BEGIN TRANSACTION}} msg]
  execsql {ROLLBACK}
  lappend r $msg
} {1 {cannot start a transaction within a transaction}}
integrity_check lock-3.2

do_test lock-999.1 {
  rename db2 {}
} {}

finish_test

Changes to test/trans.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
...
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
#    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 is database locks.
#
# $Id: trans.test,v 1.15 2002/08/13 00:01:18 drh Exp $


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


# Create several tables to work with.
................................................................................
integrity_check trans-3.15

do_test trans-4.1 {
  set v [catch {execsql {
    COMMIT;
  } db} msg]
  lappend v $msg
} {0 {}}
do_test trans-4.2 {
  set v [catch {execsql {
    ROLLBACK;
  } db} msg]
  lappend v $msg
} {0 {}}
do_test trans-4.3 {
  set v [catch {execsql {
    BEGIN TRANSACTION;
    SELECT a FROM two ORDER BY a;
  } db} msg]
  lappend v $msg
} {0 {1 4 5 10}}
................................................................................
} {1 {database is locked}}
do_test trans-4.6 {
  set v [catch {execsql {
    BEGIN TRANSACTION;
    SELECT a FROM one ORDER BY a;
  } db} msg]
  lappend v $msg
} {0 {1 2 3 4}}
do_test trans-4.7 {
  set v [catch {execsql {
    SELECT a FROM two ORDER BY a;
  } altdb} msg]
  lappend v $msg
} {1 {database is locked}}
do_test trans-4.8 {







|







 







|





|







 







|







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
...
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
#    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 is database locks.
#
# $Id: trans.test,v 1.16 2002/08/18 20:28:07 drh Exp $


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


# Create several tables to work with.
................................................................................
integrity_check trans-3.15

do_test trans-4.1 {
  set v [catch {execsql {
    COMMIT;
  } db} msg]
  lappend v $msg
} {1 {cannot commit - no transaction is active}}
do_test trans-4.2 {
  set v [catch {execsql {
    ROLLBACK;
  } db} msg]
  lappend v $msg
} {1 {cannot rollback - no transaction is active}}
do_test trans-4.3 {
  set v [catch {execsql {
    BEGIN TRANSACTION;
    SELECT a FROM two ORDER BY a;
  } db} msg]
  lappend v $msg
} {0 {1 4 5 10}}
................................................................................
} {1 {database is locked}}
do_test trans-4.6 {
  set v [catch {execsql {
    BEGIN TRANSACTION;
    SELECT a FROM one ORDER BY a;
  } db} msg]
  lappend v $msg
} {1 {cannot start a transaction within a transaction}}
do_test trans-4.7 {
  set v [catch {execsql {
    SELECT a FROM two ORDER BY a;
  } altdb} msg]
  lappend v $msg
} {1 {database is locked}}
do_test trans-4.8 {

Changes to test/trigger3.test.

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
        INSERT INTO tbl VALUES (5, 5, 6);
        INSERT INTO tbl VALUES (3, 5, 6);
    }
} {1 {Trigger rollback}}
do_test trig-raise-3.2 {
    execsql {
	SELECT * FROM tbl;
	ROLLBACK;
    }
} {}
# IGNORE
do_test trig-raise-4.1 {
    catchsql {
	BEGIN;
        INSERT INTO tbl VALUES (5, 5, 6);







<







65
66
67
68
69
70
71

72
73
74
75
76
77
78
        INSERT INTO tbl VALUES (5, 5, 6);
        INSERT INTO tbl VALUES (3, 5, 6);
    }
} {1 {Trigger rollback}}
do_test trig-raise-3.2 {
    execsql {
	SELECT * FROM tbl;

    }
} {}
# IGNORE
do_test trig-raise-4.1 {
    catchsql {
	BEGIN;
        INSERT INTO tbl VALUES (5, 5, 6);