/ Check-in [2eb6d3e4]
Login

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

Overview
Comment:Add new test file e_walhook.test.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 2eb6d3e4fbe388ef28e4b7b846e9e8a4361517a4
User & Date: dan 2014-12-10 20:29:49
Context
2014-12-10
20:57
Fix a typo causing a test error in e_walhook.test. check-in: d9f916ba user: dan tags: trunk
20:29
Add new test file e_walhook.test. check-in: 2eb6d3e4 user: dan tags: trunk
17:34
Revise mutex handling by the sqlite3_win32_reset_heap() function. check-in: eacb3b7b user: mistachkin tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/sqlite.h.in.

  7176   7176   */
  7177   7177   void sqlite3_log(int iErrCode, const char *zFormat, ...);
  7178   7178   
  7179   7179   /*
  7180   7180   ** CAPI3REF: Write-Ahead Log Commit Hook
  7181   7181   **
  7182   7182   ** ^The [sqlite3_wal_hook()] function is used to register a callback that
  7183         -** will be invoked each time a database connection commits data to a
  7184         -** [write-ahead log] (i.e. whenever a transaction is committed in
  7185         -** [journal_mode | journal_mode=WAL mode]). 
         7183  +** is invoked each time data is committed to a database in wal mode.
  7186   7184   **
  7187         -** ^The callback is invoked by SQLite after the commit has taken place and 
  7188         -** the associated write-lock on the database released, so the implementation 
         7185  +** ^(The callback is invoked by SQLite after the commit has taken place and 
         7186  +** the associated write-lock on the database released)^, so the implementation 
  7189   7187   ** may read, write or [checkpoint] the database as required.
  7190   7188   **
  7191   7189   ** ^The first parameter passed to the callback function when it is invoked
  7192   7190   ** is a copy of the third parameter passed to sqlite3_wal_hook() when
  7193   7191   ** registering the callback. ^The second is a copy of the database handle.
  7194   7192   ** ^The third parameter is the name of the database that was written to -
  7195   7193   ** either "main" or the name of an [ATTACH]-ed database. ^The fourth parameter

Changes to src/tclsqlite.c.

   631    631   ){
   632    632     int ret = SQLITE_OK;
   633    633     Tcl_Obj *p;
   634    634     SqliteDb *pDb = (SqliteDb*)clientData;
   635    635     Tcl_Interp *interp = pDb->interp;
   636    636     assert(pDb->pWalHook);
   637    637   
          638  +  assert( db==pDb->db );
   638    639     p = Tcl_DuplicateObj(pDb->pWalHook);
   639    640     Tcl_IncrRefCount(p);
   640    641     Tcl_ListObjAppendElement(interp, p, Tcl_NewStringObj(zDb, -1));
   641    642     Tcl_ListObjAppendElement(interp, p, Tcl_NewIntObj(nEntry));
   642    643     if( TCL_OK!=Tcl_EvalObjEx(interp, p, 0) 
   643    644      || TCL_OK!=Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp), &ret)
   644    645     ){

Added test/e_walhook.test.

            1  +# 2014 December 04
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +#
           12  +
           13  +set testdir [file dirname $argv0]
           14  +source $testdir/tester.tcl
           15  +source $testdir/wal_common.tcl
           16  +set testprefix e_walhook
           17  +
           18  +
           19  +# EVIDENCE-OF: R-00752-43975 The sqlite3_wal_hook() function is used to
           20  +# register a callback that is invoked each time data is committed to a
           21  +# database in wal mode.
           22  +#
           23  +#   1.1: shows that the wal-hook is not invoked in rollback mode.
           24  +#   1.2: but is invoked in wal mode.
           25  +#
           26  +set ::wal_hook_count 0
           27  +proc my_wal_hook {args} {
           28  +  incr ::wal_hook_count
           29  +  return 0
           30  +}
           31  +
           32  +do_test 1.1.1 {
           33  +  db wal_hook my_wal_hook
           34  +  execsql {
           35  +    CREATE TABLE t1(x);
           36  +    INSERT INTO t1 VALUES(1);
           37  +  }
           38  +  set ::wal_hook_count
           39  +} 0
           40  +do_test 1.1.2 {
           41  +  execsql { PRAGMA journal_mode = wal }
           42  +  set ::wal_hook_count
           43  +} 0
           44  +
           45  +do_test 1.3 {
           46  +  execsql { INSERT INTO t1 VALUES(2) }
           47  +  set wal_hook_count
           48  +} 1
           49  +
           50  +do_test 1.4 {
           51  +  execsql { 
           52  +    BEGIN;
           53  +      INSERT INTO t1 VALUES(3);
           54  +      INSERT INTO t1 VALUES(4);
           55  +    COMMIT;
           56  +  }
           57  +  set wal_hook_count
           58  +} 2
           59  +
           60  +# EVIDENCE-OF: R-65366-15139 The callback is invoked by SQLite after the
           61  +# commit has taken place and the associated write-lock on the database
           62  +# released
           63  +#
           64  +set ::read_ok 0
           65  +proc my_wal_hook {args} {
           66  +  sqlite3 db2 test.db
           67  +  if {[db2 eval { SELECT * FROM t1 }] == "1 2 3 4 5"} {
           68  +    set ::read_ok 1
           69  +  }
           70  +  db2 close
           71  +}
           72  +do_test 2.1 {
           73  +  execsql { INSERT INTO t1 VALUES(5) }
           74  +  set ::read_ok
           75  +} 1
           76  +
           77  +# EVIDENCE-OF: R-44294-52863 The third parameter is the name of the
           78  +# database that was written to - either "main" or the name of an
           79  +# ATTACH-ed database.
           80  +#
           81  +# EVIDENCE-OF: R-18913-19355 The fourth parameter is the number of pages
           82  +# currently in the write-ahead log file, including those that were just
           83  +# committed.
           84  +#
           85  +set ::wal_hook_args [list]
           86  +proc my_wal_hook {dbname nEntry} {
           87  +  set ::wal_hook_args [list $dbname $nEntry]
           88  +}
           89  +forcedelete test.db2
           90  +do_test 3.0 {
           91  +  execsql {
           92  +    ATTACH 'test.db2' AS aux;
           93  +    CREATE TABLE aux.t2(x);
           94  +    PRAGMA aux.journal_mode = wal;
           95  +  }
           96  +} {wal}
           97  +
           98  +# Database "aux"
           99  +do_test 3.1.1 {
          100  +  set wal_hook_args [list]
          101  +  execsql { INSERT INTO t2 VALUES('a') }
          102  +} {}
          103  +do_test 3.1.2 {
          104  +  set wal_hook_args
          105  +} [list aux [wal_frame_count test.db2-wal 1024]]
          106  +
          107  +# Database "main"
          108  +do_test 3.2.1 {
          109  +  set wal_hook_args [list]
          110  +  execsql { INSERT INTO t1 VALUES(6) }
          111  +} {}
          112  +do_test 3.1.2 {
          113  +  set wal_hook_args
          114  +} [list main [wal_frame_count test.db-wal 1024]]
          115  +
          116  +# EVIDENCE-OF: R-14034-00929 If an error code is returned, that error
          117  +# will propagate back up through the SQLite code base to cause the
          118  +# statement that provoked the callback to report an error, though the
          119  +# commit will have still occurred.
          120  +#
          121  +proc my_wal_hook {args} { return 1 ;# SQLITE_ERROR }
          122  +do_catchsql_test 4.1 {
          123  +  INSERT INTO t1 VALUES(7)
          124  +} {1 {SQL logic error or missing database}}
          125  +
          126  +proc my_wal_hook {args} { return 5 ;# SQLITE_BUSY }
          127  +do_catchsql_test 4.2 {
          128  +  INSERT INTO t1 VALUES(8)
          129  +} {1 {database is locked}}
          130  +
          131  +proc my_wal_hook {args} { return 14 ;# SQLITE_CANTOPEN }
          132  +do_catchsql_test 4.3 {
          133  +  INSERT INTO t1 VALUES(9)
          134  +} {1 {unable to open database file}}
          135  +
          136  +do_execsql_test 4.4 {
          137  +  SELECT * FROM t1
          138  +} {1 2 3 4 5 6 7 8 9}
          139  +
          140  +# EVIDENCE-OF: R-10466-53920 Calling sqlite3_wal_hook() replaces any
          141  +# previously registered write-ahead log callback.
          142  +set ::old_wal_hook 0
          143  +proc my_old_wal_hook {args} {
          144  +  incr ::old_wal_hook 
          145  +  return 0
          146  +}
          147  +db wal_hook my_old_wal_hook
          148  +do_test 5.1 {
          149  +  execsql { INSERT INTO t1 VALUES(10) }
          150  +  set ::old_wal_hook
          151  +} {1}
          152  +
          153  +# Replace old_wal_hook. Observe that it is not invoked after it has 
          154  +# been replaced.
          155  +proc my_new_wal_hook {args} { return 0 }
          156  +db wal_hook my_new_wal_hook
          157  +do_test 5.2 {
          158  +  execsql { INSERT INTO t1 VALUES(11) }
          159  +  set ::old_wal_hook
          160  +} {1}
          161  +
          162  +
          163  +
          164  +# EVIDENCE-OF: R-42842-27162 Note that the sqlite3_wal_autocheckpoint()
          165  +# interface and the wal_autocheckpoint pragma both invoke
          166  +# sqlite3_wal_hook() and will those overwrite any prior
          167  +# sqlite3_wal_hook() settings.
          168  +#
          169  +set ::old_wal_hook 0
          170  +proc my_old_wal_hook {args} { incr ::old_wal_hook ; return 0 }
          171  +do_test 6.1.1 {
          172  +  execsql { INSERT INTO t1 VALUES(12) }
          173  +  set ::old_wal_hook
          174  +} {1}
          175  +do_test 6.1.2 {
          176  +  execsql { PRAGA wal_autocheckpoint = 1000 }
          177  +  execsql { INSERT INTO t1 VALUES(12) }
          178  +  set ::old_wal_hook
          179  +} {1}
          180  +
          181  +# EVIDENCE-OF: R-52629-38967 The first parameter passed to the callback
          182  +# function when it is invoked is a copy of the third parameter passed to
          183  +# sqlite3_wal_hook() when registering the callback.
          184  +#
          185  +#    This is tricky to test using the tcl interface. However, the
          186  +#    mechanism used to invoke the tcl script registered as a wal-hook
          187  +#    depends on the context pointer being correctly passed through. And
          188  +#    since multiple different wal-hook scripts have been successfully
          189  +#    invoked by this test script, consider this tested.
          190  +#
          191  +# EVIDENCE-OF: R-23378-42536 The second is a copy of the database
          192  +# handle.
          193  +#
          194  +#    There is an assert() in the C wal-hook used by tclsqlite.c to
          195  +#    prove this. And that hook has been invoked multiple times when
          196  +#    running this script. So consider this requirement tested as well.
          197  +#
          198  +
          199  +finish_test