SQLite

Check-in [27ae406537]
Login

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

Overview
Comment:When the commit_hook calls a query recursively, make sure the commit_hook is not invoked recursively. Ticket #3564. (CVS 6107)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 27ae406537c07073db46ecde40c65c78fbb73170
User & Date: drh 2009-01-03 14:04:39.000
Context
2009-01-03
15:06
Add some tests with attached databases to savepoint.test. Also tests of creating and dropping tables in auto-vacuum mode inside of a savepoint. (CVS 6108) (check-in: ca7f11d50d user: danielk1977 tags: trunk)
14:04
When the commit_hook calls a query recursively, make sure the commit_hook is not invoked recursively. Ticket #3564. (CVS 6107) (check-in: 27ae406537 user: drh tags: trunk)
12:55
Fix a typo in a comment. (CVS 6106) (check-in: 50f57cd145 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/sqliteInt.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2001 September 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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.819 2009/01/03 12:55:18 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Include the configuration header output by 'configure' if we're using the
** autoconf-based build













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
** 2001 September 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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.820 2009/01/03 14:04:39 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Include the configuration header output by 'configure' if we're using the
** autoconf-based build
806
807
808
809
810
811
812

813
814
815
816
817
818
819
#define SQLITE_LegacyFileFmt  0x00008000  /* Create new databases in format 1 */
#define SQLITE_FullFSync      0x00010000  /* Use full fsync on the backend */
#define SQLITE_LoadExtension  0x00020000  /* Enable load_extension */

#define SQLITE_RecoveryMode   0x00040000  /* Ignore schema errors */
#define SQLITE_SharedCache    0x00080000  /* Cache sharing is enabled */
#define SQLITE_Vtab           0x00100000  /* There exists a virtual table */


/*
** Possible values for the sqlite.magic field.
** The numbers are obtained at random and have no special meaning, other
** than being distinct from one another.
*/
#define SQLITE_MAGIC_OPEN     0xa029a697  /* Database is open */







>







806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
#define SQLITE_LegacyFileFmt  0x00008000  /* Create new databases in format 1 */
#define SQLITE_FullFSync      0x00010000  /* Use full fsync on the backend */
#define SQLITE_LoadExtension  0x00020000  /* Enable load_extension */

#define SQLITE_RecoveryMode   0x00040000  /* Ignore schema errors */
#define SQLITE_SharedCache    0x00080000  /* Cache sharing is enabled */
#define SQLITE_Vtab           0x00100000  /* There exists a virtual table */
#define SQLITE_CommitBusy     0x00200000  /* In the process of committing */

/*
** Possible values for the sqlite.magic field.
** The numbers are obtained at random and have no special meaning, other
** than being distinct from one another.
*/
#define SQLITE_MAGIC_OPEN     0xa029a697  /* Database is open */
Changes to src/vdbeaux.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** This file contains code used for creating, destroying, and populating
** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.)  Prior
** to version 2.8.7, all this code was combined into the vdbe.c source file.
** But that file was getting too big so this subroutines were split out.
**
** $Id: vdbeaux.c,v 1.428 2008/12/16 17:20:38 shane Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include "vdbeInt.h"










|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** This file contains code used for creating, destroying, and populating
** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.)  Prior
** to version 2.8.7, all this code was combined into the vdbe.c source file.
** But that file was getting too big so this subroutines were split out.
**
** $Id: vdbeaux.c,v 1.429 2009/01/03 14:04:39 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include "vdbeInt.h"



1272
1273
1274
1275
1276
1277
1278


1279
1280
1281

1282
1283
1284
1285
1286
1287
1288
      needXcommit = 1;
      if( i!=1 ) nTrans++;
    }
  }

  /* If there are any write-transactions at all, invoke the commit hook */
  if( needXcommit && db->xCommitCallback ){


    (void)sqlite3SafetyOff(db);
    rc = db->xCommitCallback(db->pCommitArg);
    (void)sqlite3SafetyOn(db);

    if( rc ){
      return SQLITE_CONSTRAINT;
    }
  }

  /* The simple case - no more than one database file (not counting the
  ** TEMP database) has a transaction active.   There is no need for the







>
>



>







1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
      needXcommit = 1;
      if( i!=1 ) nTrans++;
    }
  }

  /* If there are any write-transactions at all, invoke the commit hook */
  if( needXcommit && db->xCommitCallback ){
    assert( (db->flags & SQLITE_CommitBusy)==0 );
    db->flags |= SQLITE_CommitBusy;
    (void)sqlite3SafetyOff(db);
    rc = db->xCommitCallback(db->pCommitArg);
    (void)sqlite3SafetyOn(db);
    db->flags &= ~SQLITE_CommitBusy;
    if( rc ){
      return SQLITE_CONSTRAINT;
    }
  }

  /* The simple case - no more than one database file (not counting the
  ** TEMP database) has a transaction active.   There is no need for the
1590
1591
1592
1593
1594
1595
1596

1597
1598
1599
1600
1601
1602
1603
    **
    ** Note: This block also runs if one of the special errors handled 
    ** above has occurred. 
    */
    if( !sqlite3VtabInSync(db) 
     && db->autoCommit 
     && db->writeVdbeCnt==(p->readOnly==0) 

    ){
      if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){
        /* The auto-commit flag is true, and the vdbe program was 
        ** successful or hit an 'OR FAIL' constraint. This means a commit 
        ** is required.
        */
        int rc = vdbeCommit(db, p);







>







1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
    **
    ** Note: This block also runs if one of the special errors handled 
    ** above has occurred. 
    */
    if( !sqlite3VtabInSync(db) 
     && db->autoCommit 
     && db->writeVdbeCnt==(p->readOnly==0) 
     && (db->flags & SQLITE_CommitBusy)==0
    ){
      if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){
        /* The auto-commit flag is true, and the vdbe program was 
        ** successful or hit an 'OR FAIL' constraint. This means a commit 
        ** is required.
        */
        int rc = vdbeCommit(db, p);
Changes to test/hook.test.
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#
# The focus of the tests in this file is the  following interface:
#
#      sqlite_commit_hook    (tests hook-1..hook-3 inclusive)
#      sqlite_update_hook    (tests hook-4-*)
#      sqlite_rollback_hook  (tests hook-5.*)
#
# $Id: hook.test,v 1.13 2008/01/19 20:11:26 drh Exp $

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

do_test hook-1.2 {
  db commit_hook
} {}







|







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#
# The focus of the tests in this file is the  following interface:
#
#      sqlite_commit_hook    (tests hook-1..hook-3 inclusive)
#      sqlite_update_hook    (tests hook-4-*)
#      sqlite_rollback_hook  (tests hook-5.*)
#
# $Id: hook.test,v 1.14 2009/01/03 14:04:39 drh Exp $

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

do_test hook-1.2 {
  db commit_hook
} {}
87
88
89
90
91
92
93





















94
95
96
97
98
99
100
  db commit_hook {}
  set ::commit_cnt {}
  execsql {
    INSERT INTO t2 VALUES(7,8);
  }
  set ::commit_cnt
} {}






















#----------------------------------------------------------------------------
# Tests for the update-hook.
#
# 4.1.* - Very simple tests. Test that the update hook is invoked correctly 
#         for INSERT, DELETE and UPDATE statements, including DELETE 
#         statements with no WHERE clause.







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







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
  db commit_hook {}
  set ::commit_cnt {}
  execsql {
    INSERT INTO t2 VALUES(7,8);
  }
  set ::commit_cnt
} {}

# Ticket #3564.
#
do_test hook-3.10 {
  file delete -force test2.db test2.db-journal
  sqlite3 db2 test2.db
  proc commit_hook {} {
    set y [db2 one {SELECT y FROM t3 WHERE y>10}]
    return [expr {$y>10}]
  }
  db2 eval {CREATE TABLE t3(x,y)}
  db2 commit_hook commit_hook
  catchsql {INSERT INTO t3 VALUES(1,2)} db2
  catchsql {INSERT INTO t3 VALUES(11,12)} db2
  catchsql {INSERT INTO t3 VALUES(3,4)} db2
  db2 eval {
    SELECT * FROM t3 ORDER BY x;
  }
} {1 2 3 4}
db2 close


#----------------------------------------------------------------------------
# Tests for the update-hook.
#
# 4.1.* - Very simple tests. Test that the update hook is invoked correctly 
#         for INSERT, DELETE and UPDATE statements, including DELETE 
#         statements with no WHERE clause.