xref: /sqlite-3.40.0/test/shared_err.test (revision b94bf855)
1# 2005 December 30
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# The focus of the tests in this file are IO errors that occur in a shared
13# cache context. What happens to connection B if one connection A encounters
14# an IO-error whilst reading or writing the file-system?
15#
16# $Id: shared_err.test,v 1.10 2007/03/19 13:53:38 danielk1977 Exp $
17
18proc skip {args} {}
19
20
21set testdir [file dirname $argv0]
22source $testdir/tester.tcl
23db close
24
25ifcapable !shared_cache||!subquery {
26  finish_test
27  return
28}
29set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
30
31# Todo: This is a copy of the [do_malloc_test] proc in malloc.test
32# It would be better if these were consolidated.
33
34# Usage: do_malloc_test <test number> <options...>
35#
36# The first argument, <test number>, is an integer used to name the
37# tests executed by this proc. Options are as follows:
38#
39#     -tclprep          TCL script to run to prepare test.
40#     -sqlprep          SQL script to run to prepare test.
41#     -tclbody          TCL script to run with malloc failure simulation.
42#     -sqlbody          TCL script to run with malloc failure simulation.
43#     -cleanup          TCL script to run after the test.
44#
45# This command runs a series of tests to verify SQLite's ability
46# to handle an out-of-memory condition gracefully. It is assumed
47# that if this condition occurs a malloc() call will return a
48# NULL pointer. Linux, for example, doesn't do that by default. See
49# the "BUGS" section of malloc(3).
50#
51# Each iteration of a loop, the TCL commands in any argument passed
52# to the -tclbody switch, followed by the SQL commands in any argument
53# passed to the -sqlbody switch are executed. Each iteration the
54# Nth call to sqliteMalloc() is made to fail, where N is increased
55# each time the loop runs starting from 1. When all commands execute
56# successfully, the loop ends.
57#
58proc do_malloc_test {tn args} {
59  array unset ::mallocopts
60  array set ::mallocopts $args
61
62  set ::go 1
63  for {set ::n 1} {$::go && $::n < 50000} {incr ::n} {
64    do_test shared_malloc-$tn.$::n {
65
66      # Remove all traces of database files test.db and test2.db from the files
67      # system. Then open (empty database) "test.db" with the handle [db].
68      #
69      sqlite_malloc_fail 0
70      catch {db close}
71      catch {file delete -force test.db}
72      catch {file delete -force test.db-journal}
73      catch {file delete -force test2.db}
74      catch {file delete -force test2.db-journal}
75      catch {sqlite3 db test.db}
76      set ::DB [sqlite3_connection_pointer db]
77
78      # Execute any -tclprep and -sqlprep scripts.
79      #
80      if {[info exists ::mallocopts(-tclprep)]} {
81        eval $::mallocopts(-tclprep)
82      }
83      if {[info exists ::mallocopts(-sqlprep)]} {
84        execsql $::mallocopts(-sqlprep)
85      }
86
87      # Now set the ${::n}th malloc() to fail and execute the -tclbody and
88      # -sqlbody scripts.
89      #
90      sqlite_malloc_fail $::n
91      set ::mallocbody {}
92      if {[info exists ::mallocopts(-tclbody)]} {
93        append ::mallocbody "$::mallocopts(-tclbody)\n"
94      }
95      if {[info exists ::mallocopts(-sqlbody)]} {
96        append ::mallocbody "db eval {$::mallocopts(-sqlbody)}"
97      }
98      set v [catch $::mallocbody msg]
99
100      set leftover [lindex [sqlite_malloc_stat] 2]
101      if {$leftover>0} {
102        if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v  Message=$msg"}
103        set ::go 0
104        if {$v} {
105          puts "\nError message returned: $msg"
106        } else {
107          set v {1 1}
108        }
109      } else {
110        set v2 [expr {$msg=="" || $msg=="out of memory"}]
111        if {!$v2} {puts "\nError message returned: $msg"}
112        lappend v $v2
113      }
114    } {1 1}
115
116    sqlite_malloc_fail 0
117    if {[info exists ::mallocopts(-cleanup)]} {
118      catch [list uplevel #0 $::mallocopts(-cleanup)] msg
119    }
120  }
121  unset ::mallocopts
122}
123
124
125do_ioerr_test shared_ioerr-1 -tclprep {
126  sqlite3 db2 test.db
127  execsql {
128    PRAGMA read_uncommitted = 1;
129    CREATE TABLE t1(a,b,c);
130    BEGIN;
131    SELECT * FROM sqlite_master;
132  } db2
133} -sqlbody {
134  SELECT * FROM sqlite_master;
135  INSERT INTO t1 VALUES(1,2,3);
136  BEGIN TRANSACTION;
137  INSERT INTO t1 VALUES(1,2,3);
138  INSERT INTO t1 VALUES(4,5,6);
139  ROLLBACK;
140  SELECT * FROM t1;
141  BEGIN TRANSACTION;
142  INSERT INTO t1 VALUES(1,2,3);
143  INSERT INTO t1 VALUES(4,5,6);
144  COMMIT;
145  SELECT * FROM t1;
146  DELETE FROM t1 WHERE a<100;
147} -cleanup {
148  do_test shared_ioerr-1.$n.cleanup.1 {
149    set res [catchsql {
150      SELECT * FROM t1;
151    } db2]
152    set possible_results [list            \
153      "1 {disk I/O error}"                \
154      "0 {1 2 3}"                         \
155      "0 {1 2 3 1 2 3 4 5 6}"             \
156      "0 {1 2 3 1 2 3 4 5 6 1 2 3 4 5 6}" \
157      "0 {}"                              \
158    ]
159    set rc [expr [lsearch -exact $possible_results $res] >= 0]
160    if {$rc != 1} {
161      puts ""
162      puts "Result: $res"
163    }
164    set rc
165  } {1}
166  db2 close
167}
168
169do_ioerr_test shared_ioerr-2 -tclprep {
170  sqlite3 db2 test.db
171  execsql {
172    PRAGMA read_uncommitted = 1;
173    BEGIN;
174    CREATE TABLE t1(a, b);
175    INSERT INTO t1(oid) VALUES(NULL);
176    INSERT INTO t1(oid) SELECT NULL FROM t1;
177    INSERT INTO t1(oid) SELECT NULL FROM t1;
178    INSERT INTO t1(oid) SELECT NULL FROM t1;
179    INSERT INTO t1(oid) SELECT NULL FROM t1;
180    INSERT INTO t1(oid) SELECT NULL FROM t1;
181    INSERT INTO t1(oid) SELECT NULL FROM t1;
182    INSERT INTO t1(oid) SELECT NULL FROM t1;
183    INSERT INTO t1(oid) SELECT NULL FROM t1;
184    INSERT INTO t1(oid) SELECT NULL FROM t1;
185    INSERT INTO t1(oid) SELECT NULL FROM t1;
186    UPDATE t1 set a = oid, b = 'abcdefghijklmnopqrstuvwxyz0123456789';
187    CREATE INDEX i1 ON t1(a);
188    COMMIT;
189    BEGIN;
190    SELECT * FROM sqlite_master;
191  } db2
192} -tclbody {
193  set ::residx 0
194  execsql {DELETE FROM t1 WHERE 0 = (a % 2);}
195  incr ::residx
196
197  # When this transaction begins the table contains 512 entries. The
198  # two statements together add 512+146 more if it succeeds.
199  # (1024/7==146)
200  execsql {BEGIN;}
201  execsql {INSERT INTO t1 SELECT a+1, b FROM t1;}
202  execsql {INSERT INTO t1 SELECT 'string' || a, b FROM t1 WHERE 0 = (a%7);}
203  execsql {COMMIT;}
204
205  incr ::residx
206} -cleanup {
207  do_test shared_ioerr-2.$n.cleanup.1 {
208    set res [catchsql {
209      SELECT max(a), min(a), count(*) FROM (SELECT a FROM t1 order by a);
210    } db2]
211    set possible_results [list \
212      {0 {1024 1 1024}}        \
213      {0 {1023 1 512}}         \
214      {0 {string994 1 1170}}   \
215    ]
216    set idx [lsearch -exact $possible_results $res]
217    set success [expr {$idx==$::residx || $res=="1 {disk I/O error}"}]
218    if {!$success} {
219      puts ""
220      puts "Result: \"$res\" ($::residx)"
221    }
222    set success
223  } {1}
224  db2 close
225}
226
227# This test is designed to provoke an IO error when a cursor position is
228# "saved" (because another cursor is going to modify the underlying table).
229#
230do_ioerr_test shared_ioerr-3 -tclprep {
231  sqlite3 db2 test.db
232  execsql {
233    PRAGMA read_uncommitted = 1;
234    PRAGMA cache_size = 10;
235    BEGIN;
236    CREATE TABLE t1(a, b, UNIQUE(a, b));
237  } db2
238  for {set i 0} {$i < 200} {incr i} {
239    set a [string range [string repeat "[format %03d $i]." 5] 0 end-1]
240
241    set b [string repeat $i 2000]
242    execsql {INSERT INTO t1 VALUES($a, $b)} db2
243  }
244  execsql {COMMIT} db2
245  set ::DB2 [sqlite3_connection_pointer db2]
246  set ::STMT [sqlite3_prepare $::DB2 "SELECT a FROM t1 ORDER BY a" -1 DUMMY]
247  sqlite3_step $::STMT       ;# Cursor points at 000.000.000.000
248  sqlite3_step $::STMT       ;# Cursor points at 001.001.001.001
249
250} -tclbody {
251  execsql {
252    BEGIN;
253    INSERT INTO t1 VALUES('201.201.201.201.201', NULL);
254    UPDATE t1 SET a = '202.202.202.202.202' WHERE a LIKE '201%';
255    COMMIT;
256  }
257} -cleanup {
258  set ::steprc  [sqlite3_step $::STMT]
259  set ::column  [sqlite3_column_text $::STMT 0]
260  set ::finalrc [sqlite3_finalize $::STMT]
261
262  # There are three possible outcomes here (assuming persistent IO errors):
263  #
264  # 1. If the [sqlite3_step] did not require any IO (required pages in
265  #    the cache), then the next row ("002...") may be retrieved
266  #    successfully.
267  #
268  # 2. If the [sqlite3_step] does require IO, then [sqlite3_step] returns
269  #    SQLITE_ERROR and [sqlite3_finalize] returns IOERR.
270  #
271  # 3. If, after the initial IO error, SQLite tried to rollback the
272  #    active transaction and a second IO error was encountered, then
273  #    statement $::STMT will have been aborted. This means [sqlite3_stmt]
274  #    returns SQLITE_ABORT, and the statement cursor does not move. i.e.
275  #    [sqlite3_column] still returns the current row ("001...") and
276  #    [sqlite3_finalize] returns SQLITE_OK.
277  #
278
279  do_test shared_ioerr-3.$n.cleanup.1 {
280    expr {
281      $::steprc eq "SQLITE_ROW" ||
282      $::steprc eq "SQLITE_ERROR" ||
283      $::steprc eq "SQLITE_ABORT"
284    }
285  } {1}
286  do_test shared_ioerr-3.$n.cleanup.2 {
287    expr {
288      ($::steprc eq "SQLITE_ROW" && $::column eq "002.002.002.002.002") ||
289      ($::steprc eq "SQLITE_ERROR" && $::column eq "") ||
290      ($::steprc eq "SQLITE_ABORT" && $::column eq "001.001.001.001.001")
291    }
292  } {1}
293  do_test shared_ioerr-3.$n.cleanup.3 {
294    expr {
295      ($::steprc eq "SQLITE_ROW" && $::finalrc eq "SQLITE_OK") ||
296      ($::steprc eq "SQLITE_ERROR" && $::finalrc eq "SQLITE_IOERR") ||
297      ($::steprc eq "SQLITE_ABORT" && $::finalrc eq "SQLITE_OK")
298    }
299  } {1}
300
301# db2 eval {select * from sqlite_master}
302  db2 close
303}
304
305# Only run these tests if memory debugging is turned on.
306#
307if {[info command sqlite_malloc_stat]==""} {
308   puts "Skipping malloc tests: not compiled with -DSQLITE_MEMDEBUG..."
309   db close
310   sqlite3_enable_shared_cache $::enable_shared_cache
311   finish_test
312   return
313}
314
315# Provoke a malloc() failure when a cursor position is being saved. This
316# only happens with index cursors (because they malloc() space to save the
317# current key value). It does not happen with tables, because an integer
318# key does not require a malloc() to store.
319#
320# The library should return an SQLITE_NOMEM to the caller. The query that
321# owns the cursor (the one for which the position is not saved) should
322# continue unaffected.
323#
324do_malloc_test 4 -tclprep {
325  sqlite3 db2 test.db
326  execsql {
327    PRAGMA read_uncommitted = 1;
328    BEGIN;
329    CREATE TABLE t1(a, b, UNIQUE(a, b));
330  } db2
331  for {set i 0} {$i < 5} {incr i} {
332    set a [string repeat $i 10]
333    set b [string repeat $i 2000]
334    execsql {INSERT INTO t1 VALUES($a, $b)} db2
335  }
336  execsql {COMMIT} db2
337  set ::DB2 [sqlite3_connection_pointer db2]
338  set ::STMT [sqlite3_prepare $::DB2 "SELECT a FROM t1 ORDER BY a" -1 DUMMY]
339  sqlite3_step $::STMT       ;# Cursor points at 0000000000
340  sqlite3_step $::STMT       ;# Cursor points at 1111111111
341} -tclbody {
342  execsql {
343    INSERT INTO t1 VALUES(6, NULL);
344  }
345} -cleanup {
346  do_test shared_malloc-4.$::n.cleanup.1 {
347    set ::rc [sqlite3_step $::STMT]
348    expr {$::rc=="SQLITE_ROW" || $::rc=="SQLITE_ABORT"}
349  } {1}
350  if {$::rc=="SQLITE_ROW"} {
351    do_test shared_malloc-4.$::n.cleanup.2 {
352      sqlite3_column_text $::STMT 0
353    } {2222222222}
354  }
355  do_test shared_malloc-4.$::n.cleanup.3 {
356    sqlite3_finalize $::STMT
357  } {SQLITE_OK}
358# db2 eval {select * from sqlite_master}
359  db2 close
360}
361
362do_malloc_test 5 -tclbody {
363  sqlite3 dbX test.db
364  sqlite3 dbY test.db
365  dbX close
366  dbY close
367} -cleanup {
368  catch {dbX close}
369  catch {dbY close}
370}
371
372do_malloc_test 6 -tclbody {
373  catch {db close}
374  sqlite3_thread_cleanup
375  sqlite3_enable_shared_cache 0
376} -cleanup {
377  sqlite3_enable_shared_cache 1
378}
379
380do_test shared_misuse-7.1 {
381  sqlite3 db test.db
382  catch {
383    sqlite3_enable_shared_cache 0
384  } msg
385  set msg
386} {library routine called out of sequence}
387
388# Again provoke a malloc() failure when a cursor position is being saved,
389# this time during a ROLLBACK operation by some other handle.
390#
391# The library should return an SQLITE_NOMEM to the caller. The query that
392# owns the cursor (the one for which the position is not saved) should
393# be aborted.
394#
395set ::aborted 0
396do_malloc_test 8 -tclprep {
397  sqlite3 db2 test.db
398  execsql {
399    PRAGMA read_uncommitted = 1;
400    BEGIN;
401    CREATE TABLE t1(a, b, UNIQUE(a, b));
402  } db2
403  for {set i 0} {$i < 2} {incr i} {
404    set a [string repeat $i 10]
405    set b [string repeat $i 2000]
406    execsql {INSERT INTO t1 VALUES($a, $b)} db2
407  }
408  execsql {COMMIT} db2
409  set ::DB2 [sqlite3_connection_pointer db2]
410  set ::STMT [sqlite3_prepare $::DB2 "SELECT a FROM t1 ORDER BY a" -1 DUMMY]
411  sqlite3_step $::STMT       ;# Cursor points at 0000000000
412  sqlite3_step $::STMT       ;# Cursor points at 1111111111
413} -tclbody {
414  execsql {
415    BEGIN;
416    INSERT INTO t1 VALUES(6, NULL);
417    ROLLBACK;
418  }
419} -cleanup {
420  do_test shared_malloc-8.$::n.cleanup.1 {
421    lrange [execsql {
422      SELECT a FROM t1;
423    } db2] 0 1
424  } {0000000000 1111111111}
425  do_test shared_malloc-8.$::n.cleanup.2 {
426    set rc1 [sqlite3_step $::STMT]
427    set rc2 [sqlite3_finalize $::STMT]
428    if {$rc1=="SQLITE_ABORT"} {
429      incr ::aborted
430    }
431    expr {
432      ($rc1=="SQLITE_DONE" && $rc2=="SQLITE_OK") ||
433      ($rc1=="SQLITE_ABORT" && $rc2=="SQLITE_OK")
434    }
435  } {1}
436  db2 close
437}
438do_test shared_malloc-8.X {
439  # Test that one or more queries were aborted due to the malloc() failure.
440  expr $::aborted>=1
441} {1}
442
443catch {db close}
444sqlite3_enable_shared_cache $::enable_shared_cache
445finish_test
446