Annotation of embedaddon/sqlite3/test/malloc3.test, revision 1.1
1.1 ! misho 1: # 2005 November 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: # This file contains tests to ensure that the library handles malloc() failures
! 13: # correctly. The emphasis of these tests are the _prepare(), _step() and
! 14: # _finalize() calls.
! 15: #
! 16: # $Id: malloc3.test,v 1.24 2008/10/14 15:54:08 drh Exp $
! 17:
! 18: set testdir [file dirname $argv0]
! 19: source $testdir/tester.tcl
! 20: source $testdir/malloc_common.tcl
! 21:
! 22: # Only run these tests if memory debugging is turned on.
! 23: #
! 24: if {!$MEMDEBUG} {
! 25: puts "Skipping malloc3 tests: not compiled with -DSQLITE_MEMDEBUG..."
! 26: finish_test
! 27: return
! 28: }
! 29:
! 30: #--------------------------------------------------------------------------
! 31: # NOTES ON RECOVERING FROM A MALLOC FAILURE
! 32: #
! 33: # The tests in this file test the behaviours described in the following
! 34: # paragraphs. These tests test the behaviour of the system when malloc() fails
! 35: # inside of a call to _prepare(), _step(), _finalize() or _reset(). The
! 36: # handling of malloc() failures within ancillary procedures is tested
! 37: # elsewhere.
! 38: #
! 39: # Overview:
! 40: #
! 41: # Executing a statement is done in three stages (prepare, step and finalize). A
! 42: # malloc() failure may occur within any stage. If a memory allocation fails
! 43: # during statement preparation, no statement handle is returned. From the users
! 44: # point of view the system state is as if _prepare() had never been called.
! 45: #
! 46: # If the memory allocation fails during the _step() or _finalize() calls, then
! 47: # the database may be left in one of two states (after finalize() has been
! 48: # called):
! 49: #
! 50: # * As if the neither _step() nor _finalize() had ever been called on
! 51: # the statement handle (i.e. any changes made by the statement are
! 52: # rolled back).
! 53: # * The current transaction may be rolled back. In this case a hot-journal
! 54: # may or may not actually be present in the filesystem.
! 55: #
! 56: # The caller can tell the difference between these two scenarios by invoking
! 57: # _get_autocommit().
! 58: #
! 59: #
! 60: # Handling of sqlite3_reset():
! 61: #
! 62: # If a malloc() fails while executing an sqlite3_reset() call, this is handled
! 63: # in the same way as a failure within _finalize(). The statement handle
! 64: # is not deleted and must be passed to _finalize() for resource deallocation.
! 65: # Attempting to _step() or _reset() the statement after a failed _reset() will
! 66: # always return SQLITE_NOMEM.
! 67: #
! 68: #
! 69: # Other active SQL statements:
! 70: #
! 71: # The effect of a malloc failure on concurrently executing SQL statements,
! 72: # particularly when the statement is executing with READ_UNCOMMITTED set and
! 73: # the malloc() failure mandates statement rollback only. Currently, if
! 74: # transaction rollback is required, all other vdbe's are aborted.
! 75: #
! 76: # Non-transient mallocs in btree.c:
! 77: # * The Btree structure itself
! 78: # * Each BtCursor structure
! 79: #
! 80: # Mallocs in pager.c:
! 81: # readMasterJournal() - Space to read the master journal name
! 82: # pager_delmaster() - Space for the entire master journal file
! 83: #
! 84: # sqlite3pager_open() - The pager structure itself
! 85: # sqlite3_pagerget() - Space for a new page
! 86: # pager_open_journal() - Pager.aInJournal[] bitmap
! 87: # sqlite3pager_write() - For in-memory databases only: history page and
! 88: # statement history page.
! 89: # pager_stmt_begin() - Pager.aInStmt[] bitmap
! 90: #
! 91: # None of the above are a huge problem. The most troublesome failures are the
! 92: # transient malloc() calls in btree.c, which can occur during the tree-balance
! 93: # operation. This means the tree being balanced will be internally inconsistent
! 94: # after the malloc() fails. To avoid the corrupt tree being read by a
! 95: # READ_UNCOMMITTED query, we have to make sure the transaction or statement
! 96: # rollback occurs before sqlite3_step() returns, not during a subsequent
! 97: # sqlite3_finalize().
! 98: #--------------------------------------------------------------------------
! 99:
! 100: #--------------------------------------------------------------------------
! 101: # NOTES ON TEST IMPLEMENTATION
! 102: #
! 103: # The tests in this file are implemented differently from those in other
! 104: # files. Instead, tests are specified using three primitives: SQL, PREP and
! 105: # TEST. Each primitive has a single argument. Primitives are processed in
! 106: # the order they are specified in the file.
! 107: #
! 108: # A TEST primitive specifies a TCL script as its argument. When a TEST
! 109: # directive is encountered the Tcl script is evaluated. Usually, this Tcl
! 110: # script contains one or more calls to [do_test].
! 111: #
! 112: # A PREP primitive specifies an SQL script as its argument. When a PREP
! 113: # directive is encountered the SQL is evaluated using database connection
! 114: # [db].
! 115: #
! 116: # The SQL primitives are where the action happens. An SQL primitive must
! 117: # contain a single, valid SQL statement as its argument. When an SQL
! 118: # primitive is encountered, it is evaluated one or more times to test the
! 119: # behaviour of the system when malloc() fails during preparation or
! 120: # execution of said statement. The Nth time the statement is executed,
! 121: # the Nth malloc is said to fail. The statement is executed until it
! 122: # succeeds, i.e. (M+1) times, where M is the number of mallocs() required
! 123: # to prepare and execute the statement.
! 124: #
! 125: # Each time an SQL statement fails, the driver program (see proc [run_test]
! 126: # below) figures out if a transaction has been automatically rolled back.
! 127: # If not, it executes any TEST block immediately proceeding the SQL
! 128: # statement, then reexecutes the SQL statement with the next value of N.
! 129: #
! 130: # If a transaction has been automatically rolled back, then the driver
! 131: # program executes all the SQL specified as part of SQL or PREP primitives
! 132: # between the current SQL statement and the most recent "BEGIN". Any
! 133: # TEST block immediately proceeding the SQL statement is evaluated, and
! 134: # then the SQL statement reexecuted with the incremented N value.
! 135: #
! 136: # That make any sense? If not, read the code in [run_test] and it might.
! 137: #
! 138: # Extra restriction imposed by the implementation:
! 139: #
! 140: # * If a PREP block starts a transaction, it must finish it.
! 141: # * A PREP block may not close a transaction it did not start.
! 142: #
! 143: #--------------------------------------------------------------------------
! 144:
! 145:
! 146: # These procs are used to build up a "program" in global variable
! 147: # ::run_test_script. At the end of this file, the proc [run_test] is used
! 148: # to execute the program (and all test cases contained therein).
! 149: #
! 150: set ::run_test_script [list]
! 151: proc TEST {id t} {lappend ::run_test_script -test [list $id $t]}
! 152: proc PREP {p} {lappend ::run_test_script -prep [string trim $p]}
! 153: proc DEBUG {s} {lappend ::run_test_script -debug $s}
! 154:
! 155: # SQL --
! 156: #
! 157: # SQL ?-norollback? <sql-text>
! 158: #
! 159: # Add an 'SQL' primitive to the program (see notes above). If the -norollback
! 160: # switch is present, then the statement is not allowed to automatically roll
! 161: # back any active transaction if malloc() fails. It must rollback the statement
! 162: # transaction only.
! 163: #
! 164: proc SQL {a1 {a2 ""}} {
! 165: # An SQL primitive parameter is a list of two elements, a boolean value
! 166: # indicating if the statement may cause transaction rollback when malloc()
! 167: # fails, and the sql statement itself.
! 168: if {$a2 == ""} {
! 169: lappend ::run_test_script -sql [list true [string trim $a1]]
! 170: } else {
! 171: lappend ::run_test_script -sql [list false [string trim $a2]]
! 172: }
! 173: }
! 174:
! 175: # TEST_AUTOCOMMIT --
! 176: #
! 177: # A shorthand test to see if a transaction is active or not. The first
! 178: # argument - $id - is the integer number of the test case. The second
! 179: # argument is either 1 or 0, the expected value of the auto-commit flag.
! 180: #
! 181: proc TEST_AUTOCOMMIT {id a} {
! 182: TEST $id "do_test \$testid { sqlite3_get_autocommit \$::DB } {$a}"
! 183: }
! 184:
! 185: #--------------------------------------------------------------------------
! 186: # Start of test program declaration
! 187: #
! 188:
! 189:
! 190: # Warm body test. A malloc() fails in the middle of a CREATE TABLE statement
! 191: # in a single-statement transaction on an empty database. Not too much can go
! 192: # wrong here.
! 193: #
! 194: TEST 1 {
! 195: do_test $testid {
! 196: execsql {SELECT tbl_name FROM sqlite_master;}
! 197: } {}
! 198: }
! 199: SQL {
! 200: CREATE TABLE IF NOT EXISTS abc(a, b, c);
! 201: }
! 202: TEST 2 {
! 203: do_test $testid.1 {
! 204: execsql {SELECT tbl_name FROM sqlite_master;}
! 205: } {abc}
! 206: }
! 207:
! 208: # Insert a couple of rows into the table. each insert is in its own
! 209: # transaction. test that the table is unpopulated before running the inserts
! 210: # (and hence after each failure of the first insert), and that it has been
! 211: # populated correctly after the final insert succeeds.
! 212: #
! 213: TEST 3 {
! 214: do_test $testid.2 {
! 215: execsql {SELECT * FROM abc}
! 216: } {}
! 217: }
! 218: SQL {INSERT INTO abc VALUES(1, 2, 3);}
! 219: SQL {INSERT INTO abc VALUES(4, 5, 6);}
! 220: SQL {INSERT INTO abc VALUES(7, 8, 9);}
! 221: TEST 4 {
! 222: do_test $testid {
! 223: execsql {SELECT * FROM abc}
! 224: } {1 2 3 4 5 6 7 8 9}
! 225: }
! 226:
! 227: # Test a CREATE INDEX statement. Because the table 'abc' is so small, the index
! 228: # will all fit on a single page, so this doesn't test too much that the CREATE
! 229: # TABLE statement didn't test. A few of the transient malloc()s in btree.c
! 230: # perhaps.
! 231: #
! 232: SQL {CREATE INDEX abc_i ON abc(a, b, c);}
! 233: TEST 4 {
! 234: do_test $testid {
! 235: execsql {
! 236: SELECT * FROM abc ORDER BY a DESC;
! 237: }
! 238: } {7 8 9 4 5 6 1 2 3}
! 239: }
! 240:
! 241: # Test a DELETE statement. Also create a trigger and a view, just to make sure
! 242: # these statements don't have any obvious malloc() related bugs in them. Note
! 243: # that the test above will be executed each time the DELETE fails, so we're
! 244: # also testing rollback of a DELETE from a table with an index on it.
! 245: #
! 246: SQL {DELETE FROM abc WHERE a > 2;}
! 247: SQL {CREATE TRIGGER abc_t AFTER INSERT ON abc BEGIN SELECT 'trigger!'; END;}
! 248: SQL {CREATE VIEW abc_v AS SELECT * FROM abc;}
! 249: TEST 5 {
! 250: do_test $testid {
! 251: execsql {
! 252: SELECT name, tbl_name FROM sqlite_master ORDER BY name;
! 253: SELECT * FROM abc;
! 254: }
! 255: } {abc abc abc_i abc abc_t abc abc_v abc_v 1 2 3}
! 256: }
! 257:
! 258: set sql {
! 259: BEGIN;DELETE FROM abc;
! 260: }
! 261: for {set i 1} {$i < 15} {incr i} {
! 262: set a $i
! 263: set b "String value $i"
! 264: set c [string repeat X $i]
! 265: append sql "INSERT INTO abc VALUES ($a, '$b', '$c');"
! 266: }
! 267: append sql {COMMIT;}
! 268: PREP $sql
! 269:
! 270: SQL {
! 271: DELETE FROM abc WHERE oid IN (SELECT oid FROM abc ORDER BY random() LIMIT 5);
! 272: }
! 273: TEST 6 {
! 274: do_test $testid.1 {
! 275: execsql {SELECT count(*) FROM abc}
! 276: } {94}
! 277: do_test $testid.2 {
! 278: execsql {
! 279: SELECT min(
! 280: (oid == a) AND 'String value ' || a == b AND a == length(c)
! 281: ) FROM abc;
! 282: }
! 283: } {1}
! 284: }
! 285: SQL {
! 286: DELETE FROM abc WHERE oid IN (SELECT oid FROM abc ORDER BY random() LIMIT 5);
! 287: }
! 288: TEST 7 {
! 289: do_test $testid {
! 290: execsql {SELECT count(*) FROM abc}
! 291: } {89}
! 292: do_test $testid {
! 293: execsql {
! 294: SELECT min(
! 295: (oid == a) AND 'String value ' || a == b AND a == length(c)
! 296: ) FROM abc;
! 297: }
! 298: } {1}
! 299: }
! 300: SQL {
! 301: DELETE FROM abc WHERE oid IN (SELECT oid FROM abc ORDER BY random() LIMIT 5);
! 302: }
! 303: TEST 9 {
! 304: do_test $testid {
! 305: execsql {SELECT count(*) FROM abc}
! 306: } {84}
! 307: do_test $testid {
! 308: execsql {
! 309: SELECT min(
! 310: (oid == a) AND 'String value ' || a == b AND a == length(c)
! 311: ) FROM abc;
! 312: }
! 313: } {1}
! 314: }
! 315:
! 316: set padding [string repeat X 500]
! 317: PREP [subst {
! 318: DROP TABLE abc;
! 319: CREATE TABLE abc(a PRIMARY KEY, padding, b, c);
! 320: INSERT INTO abc VALUES(0, '$padding', 2, 2);
! 321: INSERT INTO abc VALUES(3, '$padding', 5, 5);
! 322: INSERT INTO abc VALUES(6, '$padding', 8, 8);
! 323: }]
! 324:
! 325: TEST 10 {
! 326: do_test $testid {
! 327: execsql {SELECT a, b, c FROM abc}
! 328: } {0 2 2 3 5 5 6 8 8}
! 329: }
! 330:
! 331: SQL {BEGIN;}
! 332: SQL {INSERT INTO abc VALUES(9, 'XXXXX', 11, 12);}
! 333: TEST_AUTOCOMMIT 11 0
! 334: SQL -norollback {UPDATE abc SET a = a + 1, c = c + 1;}
! 335: TEST_AUTOCOMMIT 12 0
! 336: SQL {DELETE FROM abc WHERE a = 10;}
! 337: TEST_AUTOCOMMIT 13 0
! 338: SQL {COMMIT;}
! 339:
! 340: TEST 14 {
! 341: do_test $testid.1 {
! 342: sqlite3_get_autocommit $::DB
! 343: } {1}
! 344: do_test $testid.2 {
! 345: execsql {SELECT a, b, c FROM abc}
! 346: } {1 2 3 4 5 6 7 8 9}
! 347: }
! 348:
! 349: PREP [subst {
! 350: DROP TABLE abc;
! 351: CREATE TABLE abc(a, padding, b, c);
! 352: INSERT INTO abc VALUES(1, '$padding', 2, 3);
! 353: INSERT INTO abc VALUES(4, '$padding', 5, 6);
! 354: INSERT INTO abc VALUES(7, '$padding', 8, 9);
! 355: CREATE INDEX abc_i ON abc(a, padding, b, c);
! 356: }]
! 357:
! 358: TEST 15 {
! 359: db eval {PRAGMA cache_size = 10}
! 360: }
! 361:
! 362: SQL {BEGIN;}
! 363: SQL -norllbck {INSERT INTO abc (oid, a, padding, b, c) SELECT NULL, * FROM abc}
! 364: TEST 16 {
! 365: do_test $testid {
! 366: execsql {SELECT a, count(*) FROM abc GROUP BY a;}
! 367: } {1 2 4 2 7 2}
! 368: }
! 369: SQL -norllbck {INSERT INTO abc (oid, a, padding, b, c) SELECT NULL, * FROM abc}
! 370: TEST 17 {
! 371: do_test $testid {
! 372: execsql {SELECT a, count(*) FROM abc GROUP BY a;}
! 373: } {1 4 4 4 7 4}
! 374: }
! 375: SQL -norllbck {INSERT INTO abc (oid, a, padding, b, c) SELECT NULL, * FROM abc}
! 376: TEST 18 {
! 377: do_test $testid {
! 378: execsql {SELECT a, count(*) FROM abc GROUP BY a;}
! 379: } {1 8 4 8 7 8}
! 380: }
! 381: SQL -norllbck {INSERT INTO abc (oid, a, padding, b, c) SELECT NULL, * FROM abc}
! 382: TEST 19 {
! 383: do_test $testid {
! 384: execsql {SELECT a, count(*) FROM abc GROUP BY a;}
! 385: } {1 16 4 16 7 16}
! 386: }
! 387: SQL {COMMIT;}
! 388: TEST 21 {
! 389: do_test $testid {
! 390: execsql {SELECT a, count(*) FROM abc GROUP BY a;}
! 391: } {1 16 4 16 7 16}
! 392: }
! 393:
! 394: SQL {BEGIN;}
! 395: SQL {DELETE FROM abc WHERE oid %2}
! 396: TEST 22 {
! 397: do_test $testid {
! 398: execsql {SELECT a, count(*) FROM abc GROUP BY a;}
! 399: } {1 8 4 8 7 8}
! 400: }
! 401: SQL {DELETE FROM abc}
! 402: TEST 23 {
! 403: do_test $testid {
! 404: execsql {SELECT * FROM abc}
! 405: } {}
! 406: }
! 407: SQL {ROLLBACK;}
! 408: TEST 24 {
! 409: do_test $testid {
! 410: execsql {SELECT a, count(*) FROM abc GROUP BY a;}
! 411: } {1 16 4 16 7 16}
! 412: }
! 413:
! 414: # Test some schema modifications inside of a transaction. These should all
! 415: # cause transaction rollback if they fail. Also query a view, to cover a bit
! 416: # more code.
! 417: #
! 418: PREP {DROP VIEW abc_v;}
! 419: TEST 25 {
! 420: do_test $testid {
! 421: execsql {
! 422: SELECT name, tbl_name FROM sqlite_master;
! 423: }
! 424: } {abc abc abc_i abc}
! 425: }
! 426: SQL {BEGIN;}
! 427: SQL {CREATE TABLE def(d, e, f);}
! 428: SQL {CREATE TABLE ghi(g, h, i);}
! 429: TEST 26 {
! 430: do_test $testid {
! 431: execsql {
! 432: SELECT name, tbl_name FROM sqlite_master;
! 433: }
! 434: } {abc abc abc_i abc def def ghi ghi}
! 435: }
! 436: SQL {CREATE VIEW v1 AS SELECT * FROM def, ghi}
! 437: SQL {CREATE UNIQUE INDEX ghi_i1 ON ghi(g);}
! 438: TEST 27 {
! 439: do_test $testid {
! 440: execsql {
! 441: SELECT name, tbl_name FROM sqlite_master;
! 442: }
! 443: } {abc abc abc_i abc def def ghi ghi v1 v1 ghi_i1 ghi}
! 444: }
! 445: SQL {INSERT INTO def VALUES('a', 'b', 'c')}
! 446: SQL {INSERT INTO def VALUES(1, 2, 3)}
! 447: SQL -norollback {INSERT INTO ghi SELECT * FROM def}
! 448: TEST 28 {
! 449: do_test $testid {
! 450: execsql {
! 451: SELECT * FROM def, ghi WHERE d = g;
! 452: }
! 453: } {a b c a b c 1 2 3 1 2 3}
! 454: }
! 455: SQL {COMMIT}
! 456: TEST 29 {
! 457: do_test $testid {
! 458: execsql {
! 459: SELECT * FROM v1 WHERE d = g;
! 460: }
! 461: } {a b c a b c 1 2 3 1 2 3}
! 462: }
! 463:
! 464: # Test a simple multi-file transaction
! 465: #
! 466: forcedelete test2.db
! 467: ifcapable attach {
! 468: SQL {ATTACH 'test2.db' AS aux;}
! 469: SQL {BEGIN}
! 470: SQL {CREATE TABLE aux.tbl2(x, y, z)}
! 471: SQL {INSERT INTO tbl2 VALUES(1, 2, 3)}
! 472: SQL {INSERT INTO def VALUES(4, 5, 6)}
! 473: TEST 30 {
! 474: do_test $testid {
! 475: execsql {
! 476: SELECT * FROM tbl2, def WHERE d = x;
! 477: }
! 478: } {1 2 3 1 2 3}
! 479: }
! 480: SQL {COMMIT}
! 481: TEST 31 {
! 482: do_test $testid {
! 483: execsql {
! 484: SELECT * FROM tbl2, def WHERE d = x;
! 485: }
! 486: } {1 2 3 1 2 3}
! 487: }
! 488: }
! 489:
! 490: # Test what happens when a malloc() fails while there are other active
! 491: # statements. This changes the way sqlite3VdbeHalt() works.
! 492: TEST 32 {
! 493: if {![info exists ::STMT32]} {
! 494: set sql "SELECT name FROM sqlite_master"
! 495: set ::STMT32 [sqlite3_prepare $::DB $sql -1 DUMMY]
! 496: do_test $testid {
! 497: sqlite3_step $::STMT32
! 498: } {SQLITE_ROW}
! 499: }
! 500: }
! 501: SQL BEGIN
! 502: TEST 33 {
! 503: do_test $testid {
! 504: execsql {SELECT * FROM ghi}
! 505: } {a b c 1 2 3}
! 506: }
! 507: SQL -norollback {
! 508: -- There is a unique index on ghi(g), so this statement may not cause
! 509: -- an automatic ROLLBACK. Hence the "-norollback" switch.
! 510: INSERT INTO ghi SELECT '2'||g, h, i FROM ghi;
! 511: }
! 512: TEST 34 {
! 513: if {[info exists ::STMT32]} {
! 514: do_test $testid {
! 515: sqlite3_finalize $::STMT32
! 516: } {SQLITE_OK}
! 517: unset ::STMT32
! 518: }
! 519: }
! 520: SQL COMMIT
! 521:
! 522: #
! 523: # End of test program declaration
! 524: #--------------------------------------------------------------------------
! 525:
! 526: proc run_test {arglist iRepeat {pcstart 0} {iFailStart 1}} {
! 527: if {[llength $arglist] %2} {
! 528: error "Uneven number of arguments to TEST"
! 529: }
! 530:
! 531: for {set i 0} {$i < $pcstart} {incr i} {
! 532: set k2 [lindex $arglist [expr 2 * $i]]
! 533: set v2 [lindex $arglist [expr 2 * $i + 1]]
! 534: set ac [sqlite3_get_autocommit $::DB] ;# Auto-Commit
! 535: switch -- $k2 {
! 536: -sql {db eval [lindex $v2 1]}
! 537: -prep {db eval $v2}
! 538: }
! 539: set nac [sqlite3_get_autocommit $::DB] ;# New Auto-Commit
! 540: if {$ac && !$nac} {set begin_pc $i}
! 541: }
! 542:
! 543: db rollback_hook [list incr ::rollback_hook_count]
! 544:
! 545: set iFail $iFailStart
! 546: set pc $pcstart
! 547: while {$pc*2 < [llength $arglist]} {
! 548:
! 549: # Id of this iteration:
! 550: set k [lindex $arglist [expr 2 * $pc]]
! 551: set iterid "pc=$pc.iFail=$iFail$k"
! 552: set v [lindex $arglist [expr 2 * $pc + 1]]
! 553:
! 554: switch -- $k {
! 555:
! 556: -test {
! 557: foreach {id script} $v {}
! 558: incr pc
! 559: }
! 560:
! 561: -sql {
! 562: set ::rollback_hook_count 0
! 563:
! 564: set ac [sqlite3_get_autocommit $::DB] ;# Auto-Commit
! 565: sqlite3_memdebug_fail $iFail -repeat 0
! 566: set rc [catch {db eval [lindex $v 1]} msg] ;# True error occurs
! 567: set nac [sqlite3_get_autocommit $::DB] ;# New Auto-Commit
! 568:
! 569: if {$rc != 0 && $nac && !$ac} {
! 570: # Before [db eval] the auto-commit flag was clear. Now it
! 571: # is set. Since an error occured we assume this was not a
! 572: # commit - therefore a rollback occured. Check that the
! 573: # rollback-hook was invoked.
! 574: do_test malloc3-rollback_hook.$iterid {
! 575: set ::rollback_hook_count
! 576: } {1}
! 577: }
! 578:
! 579: set nFail [sqlite3_memdebug_fail -1 -benigncnt nBenign]
! 580: if {$rc == 0} {
! 581: # Successful execution of sql. The number of failed malloc()
! 582: # calls should be equal to the number of benign failures.
! 583: # Otherwise a malloc() failed and the error was not reported.
! 584: #
! 585: if {$nFail!=$nBenign} {
! 586: error "Unreported malloc() failure"
! 587: }
! 588:
! 589: if {$ac && !$nac} {
! 590: # Before the [db eval] the auto-commit flag was set, now it
! 591: # is clear. We can deduce that a "BEGIN" statement has just
! 592: # been successfully executed.
! 593: set begin_pc $pc
! 594: }
! 595:
! 596: incr pc
! 597: set iFail 1
! 598: integrity_check "malloc3-(integrity).$iterid"
! 599: } elseif {[regexp {.*out of memory} $msg] || [db errorcode] == 3082} {
! 600: # Out of memory error, as expected.
! 601: #
! 602: integrity_check "malloc3-(integrity).$iterid"
! 603: incr iFail
! 604: if {$nac && !$ac} {
! 605:
! 606: if {![lindex $v 0] && [db errorcode] != 3082} {
! 607: # error "Statement \"[lindex $v 1]\" caused a rollback"
! 608: }
! 609:
! 610: for {set i $begin_pc} {$i < $pc} {incr i} {
! 611: set k2 [lindex $arglist [expr 2 * $i]]
! 612: set v2 [lindex $arglist [expr 2 * $i + 1]]
! 613: set catchupsql ""
! 614: switch -- $k2 {
! 615: -sql {set catchupsql [lindex $v2 1]}
! 616: -prep {set catchupsql $v2}
! 617: }
! 618: db eval $catchupsql
! 619: }
! 620: }
! 621: } else {
! 622: error $msg
! 623: }
! 624:
! 625: while {[lindex $arglist [expr 2 * ($pc -1)]] == "-test"} {
! 626: incr pc -1
! 627: }
! 628: }
! 629:
! 630: -prep {
! 631: db eval $v
! 632: incr pc
! 633: }
! 634:
! 635: -debug {
! 636: eval $v
! 637: incr pc
! 638: }
! 639:
! 640: default { error "Unknown switch: $k" }
! 641: }
! 642: }
! 643: }
! 644:
! 645: # Turn of the Tcl interface's prepared statement caching facility. Then
! 646: # run the tests with "persistent" malloc failures.
! 647: sqlite3_extended_result_codes db 1
! 648: db cache size 0
! 649: run_test $::run_test_script 1
! 650:
! 651: # Close and reopen the db.
! 652: db close
! 653: forcedelete test.db test.db-journal test2.db test2.db-journal
! 654: sqlite3 db test.db
! 655: sqlite3_extended_result_codes db 1
! 656: set ::DB [sqlite3_connection_pointer db]
! 657:
! 658: # Turn off the Tcl interface's prepared statement caching facility in
! 659: # the new connnection. Then run the tests with "transient" malloc failures.
! 660: db cache size 0
! 661: run_test $::run_test_script 0
! 662:
! 663: sqlite3_memdebug_fail -1
! 664: finish_test
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>