Annotation of embedaddon/sqlite3/test/shared_err.test, revision 1.1
1.1 ! misho 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.24 2008/10/12 00:27:54 shane Exp $
! 17:
! 18: proc skip {args} {}
! 19:
! 20:
! 21: set testdir [file dirname $argv0]
! 22: source $testdir/tester.tcl
! 23: source $testdir/malloc_common.tcl
! 24: db close
! 25:
! 26: ifcapable !shared_cache||!subquery {
! 27: finish_test
! 28: return
! 29: }
! 30:
! 31: set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
! 32:
! 33: do_ioerr_test shared_ioerr-1 -tclprep {
! 34: sqlite3 db2 test.db
! 35: execsql {
! 36: PRAGMA read_uncommitted = 1;
! 37: CREATE TABLE t1(a,b,c);
! 38: BEGIN;
! 39: SELECT * FROM sqlite_master;
! 40: } db2
! 41: } -sqlbody {
! 42: SELECT * FROM sqlite_master;
! 43: INSERT INTO t1 VALUES(1,2,3);
! 44: BEGIN TRANSACTION;
! 45: INSERT INTO t1 VALUES(1,2,3);
! 46: INSERT INTO t1 VALUES(4,5,6);
! 47: ROLLBACK;
! 48: SELECT * FROM t1;
! 49: BEGIN TRANSACTION;
! 50: INSERT INTO t1 VALUES(1,2,3);
! 51: INSERT INTO t1 VALUES(4,5,6);
! 52: COMMIT;
! 53: SELECT * FROM t1;
! 54: DELETE FROM t1 WHERE a<100;
! 55: } -cleanup {
! 56: do_test shared_ioerr-1.$n.cleanup.1 {
! 57: set res [catchsql {
! 58: SELECT * FROM t1;
! 59: } db2]
! 60: set possible_results [list \
! 61: "1 {disk I/O error}" \
! 62: "0 {1 2 3}" \
! 63: "0 {1 2 3 1 2 3 4 5 6}" \
! 64: "0 {1 2 3 1 2 3 4 5 6 1 2 3 4 5 6}" \
! 65: "0 {}" \
! 66: "1 {database disk image is malformed}" \
! 67: ]
! 68: set rc [expr [lsearch -exact $possible_results $res] >= 0]
! 69: if {$rc != 1} {
! 70: puts ""
! 71: puts "Result: $res"
! 72: }
! 73: set rc
! 74: } {1}
! 75:
! 76: # The "database disk image is malformed" is a special case that can
! 77: # occur if an IO error occurs during a rollback in the {SELECT * FROM t1}
! 78: # statement above. This test is to make sure there is no real database
! 79: # corruption.
! 80: db2 close
! 81: do_test shared_ioerr-1.$n.cleanup.2 {
! 82: execsql {pragma integrity_check} db
! 83: } {ok}
! 84: }
! 85:
! 86: do_ioerr_test shared_ioerr-2 -tclprep {
! 87: sqlite3 db2 test.db
! 88: execsql {
! 89: PRAGMA read_uncommitted = 1;
! 90: BEGIN;
! 91: CREATE TABLE t1(a, b);
! 92: INSERT INTO t1(oid) VALUES(NULL);
! 93: INSERT INTO t1(oid) SELECT NULL FROM t1;
! 94: INSERT INTO t1(oid) SELECT NULL FROM t1;
! 95: INSERT INTO t1(oid) SELECT NULL FROM t1;
! 96: INSERT INTO t1(oid) SELECT NULL FROM t1;
! 97: INSERT INTO t1(oid) SELECT NULL FROM t1;
! 98: INSERT INTO t1(oid) SELECT NULL FROM t1;
! 99: INSERT INTO t1(oid) SELECT NULL FROM t1;
! 100: INSERT INTO t1(oid) SELECT NULL FROM t1;
! 101: INSERT INTO t1(oid) SELECT NULL FROM t1;
! 102: INSERT INTO t1(oid) SELECT NULL FROM t1;
! 103: UPDATE t1 set a = oid, b = 'abcdefghijklmnopqrstuvwxyz0123456789';
! 104: CREATE INDEX i1 ON t1(a);
! 105: COMMIT;
! 106: BEGIN;
! 107: SELECT * FROM sqlite_master;
! 108: } db2
! 109: } -tclbody {
! 110: set ::residx 0
! 111: execsql {DELETE FROM t1 WHERE 0 = (a % 2);}
! 112: incr ::residx
! 113:
! 114: # When this transaction begins the table contains 512 entries. The
! 115: # two statements together add 512+146 more if it succeeds.
! 116: # (1024/7==146)
! 117: execsql {BEGIN;}
! 118: execsql {INSERT INTO t1 SELECT a+1, b FROM t1;}
! 119: execsql {INSERT INTO t1 SELECT 'string' || a, b FROM t1 WHERE 0 = (a%7);}
! 120: execsql {COMMIT;}
! 121:
! 122: incr ::residx
! 123: } -cleanup {
! 124: catchsql ROLLBACK
! 125: do_test shared_ioerr-2.$n.cleanup.1 {
! 126: set res [catchsql {
! 127: SELECT max(a), min(a), count(*) FROM (SELECT a FROM t1 order by a);
! 128: } db2]
! 129: set possible_results [list \
! 130: {0 {1024 1 1024}} \
! 131: {0 {1023 1 512}} \
! 132: {0 {string994 1 1170}} \
! 133: ]
! 134: set idx [lsearch -exact $possible_results $res]
! 135: set success [expr {$idx==$::residx || $res=="1 {disk I/O error}"}]
! 136: if {!$success} {
! 137: puts ""
! 138: puts "Result: \"$res\" ($::residx)"
! 139: }
! 140: set success
! 141: } {1}
! 142: db2 close
! 143: }
! 144:
! 145: # This test is designed to provoke an IO error when a cursor position is
! 146: # "saved" (because another cursor is going to modify the underlying table).
! 147: #
! 148: do_ioerr_test shared_ioerr-3 -tclprep {
! 149: sqlite3 db2 test.db
! 150: execsql {
! 151: PRAGMA read_uncommitted = 1;
! 152: PRAGMA cache_size = 10;
! 153: BEGIN;
! 154: CREATE TABLE t1(a, b, UNIQUE(a, b));
! 155: } db2
! 156: for {set i 0} {$i < 200} {incr i} {
! 157: set a [string range [string repeat "[format %03d $i]." 5] 0 end-1]
! 158:
! 159: set b [string repeat $i 2000]
! 160: execsql {INSERT INTO t1 VALUES($a, $b)} db2
! 161: }
! 162: execsql {COMMIT} db2
! 163: set ::DB2 [sqlite3_connection_pointer db2]
! 164: set ::STMT [sqlite3_prepare $::DB2 "SELECT a FROM t1 ORDER BY a" -1 DUMMY]
! 165: sqlite3_step $::STMT ;# Cursor points at 000.000.000.000
! 166: sqlite3_step $::STMT ;# Cursor points at 001.001.001.001
! 167:
! 168: } -tclbody {
! 169: execsql {
! 170: BEGIN;
! 171: INSERT INTO t1 VALUES('201.201.201.201.201', NULL);
! 172: UPDATE t1 SET a = '202.202.202.202.202' WHERE a LIKE '201%';
! 173: COMMIT;
! 174: }
! 175: } -cleanup {
! 176: set ::steprc [sqlite3_step $::STMT]
! 177: set ::column [sqlite3_column_text $::STMT 0]
! 178: set ::finalrc [sqlite3_finalize $::STMT]
! 179:
! 180: # There are three possible outcomes here (assuming persistent IO errors):
! 181: #
! 182: # 1. If the [sqlite3_step] did not require any IO (required pages in
! 183: # the cache), then the next row ("002...") may be retrieved
! 184: # successfully.
! 185: #
! 186: # 2. If the [sqlite3_step] does require IO, then [sqlite3_step] returns
! 187: # SQLITE_ERROR and [sqlite3_finalize] returns IOERR.
! 188: #
! 189: # 3. If, after the initial IO error, SQLite tried to rollback the
! 190: # active transaction and a second IO error was encountered, then
! 191: # statement $::STMT will have been aborted. This means [sqlite3_stmt]
! 192: # returns SQLITE_ABORT, and the statement cursor does not move. i.e.
! 193: # [sqlite3_column] still returns the current row ("001...") and
! 194: # [sqlite3_finalize] returns SQLITE_OK.
! 195: #
! 196:
! 197: do_test shared_ioerr-3.$n.cleanup.1 {
! 198: expr {
! 199: $::steprc eq "SQLITE_ROW" ||
! 200: $::steprc eq "SQLITE_ERROR" ||
! 201: $::steprc eq "SQLITE_ABORT"
! 202: }
! 203: } {1}
! 204: do_test shared_ioerr-3.$n.cleanup.2 {
! 205: expr {
! 206: ($::steprc eq "SQLITE_ROW" && $::column eq "002.002.002.002.002") ||
! 207: ($::steprc eq "SQLITE_ERROR" && $::column eq "") ||
! 208: ($::steprc eq "SQLITE_ABORT" && $::column eq "001.001.001.001.001")
! 209: }
! 210: } {1}
! 211: do_test shared_ioerr-3.$n.cleanup.3 {
! 212: expr {
! 213: ($::steprc eq "SQLITE_ROW" && $::finalrc eq "SQLITE_OK") ||
! 214: ($::steprc eq "SQLITE_ERROR" && $::finalrc eq "SQLITE_IOERR") ||
! 215: ($::steprc eq "SQLITE_ERROR" && $::finalrc eq "SQLITE_ABORT")
! 216: }
! 217: } {1}
! 218:
! 219: # db2 eval {select * from sqlite_master}
! 220: db2 close
! 221: }
! 222:
! 223: # This is a repeat of the previous test except that this time we
! 224: # are doing a reverse-order scan of the table when the cursor is
! 225: # "saved".
! 226: #
! 227: do_ioerr_test shared_ioerr-3rev -tclprep {
! 228: sqlite3 db2 test.db
! 229: execsql {
! 230: PRAGMA read_uncommitted = 1;
! 231: PRAGMA cache_size = 10;
! 232: BEGIN;
! 233: CREATE TABLE t1(a, b, UNIQUE(a, b));
! 234: } db2
! 235: for {set i 0} {$i < 200} {incr i} {
! 236: set a [string range [string repeat "[format %03d $i]." 5] 0 end-1]
! 237:
! 238: set b [string repeat $i 2000]
! 239: execsql {INSERT INTO t1 VALUES($a, $b)} db2
! 240: }
! 241: execsql {COMMIT} db2
! 242: set ::DB2 [sqlite3_connection_pointer db2]
! 243: set ::STMT [sqlite3_prepare $::DB2 \
! 244: "SELECT a FROM t1 ORDER BY a DESC" -1 DUMMY]
! 245: sqlite3_step $::STMT ;# Cursor points at 199.199.199.199.199
! 246: sqlite3_step $::STMT ;# Cursor points at 198.198.198.198.198
! 247:
! 248: } -tclbody {
! 249: execsql {
! 250: BEGIN;
! 251: INSERT INTO t1 VALUES('201.201.201.201.201', NULL);
! 252: UPDATE t1 SET a = '202.202.202.202.202' WHERE a LIKE '201%';
! 253: COMMIT;
! 254: }
! 255: } -cleanup {
! 256: set ::steprc [sqlite3_step $::STMT]
! 257: set ::column [sqlite3_column_text $::STMT 0]
! 258: set ::finalrc [sqlite3_finalize $::STMT]
! 259:
! 260: # There are three possible outcomes here (assuming persistent IO errors):
! 261: #
! 262: # 1. If the [sqlite3_step] did not require any IO (required pages in
! 263: # the cache), then the next row ("002...") may be retrieved
! 264: # successfully.
! 265: #
! 266: # 2. If the [sqlite3_step] does require IO, then [sqlite3_step] returns
! 267: # SQLITE_ERROR and [sqlite3_finalize] returns IOERR.
! 268: #
! 269: # 3. If, after the initial IO error, SQLite tried to rollback the
! 270: # active transaction and a second IO error was encountered, then
! 271: # statement $::STMT will have been aborted. This means [sqlite3_stmt]
! 272: # returns SQLITE_ABORT, and the statement cursor does not move. i.e.
! 273: # [sqlite3_column] still returns the current row ("001...") and
! 274: # [sqlite3_finalize] returns SQLITE_OK.
! 275: #
! 276:
! 277: do_test shared_ioerr-3rev.$n.cleanup.1 {
! 278: expr {
! 279: $::steprc eq "SQLITE_ROW" ||
! 280: $::steprc eq "SQLITE_ERROR" ||
! 281: $::steprc eq "SQLITE_ABORT"
! 282: }
! 283: } {1}
! 284: do_test shared_ioerr-3rev.$n.cleanup.2 {
! 285: expr {
! 286: ($::steprc eq "SQLITE_ROW" && $::column eq "197.197.197.197.197") ||
! 287: ($::steprc eq "SQLITE_ERROR" && $::column eq "") ||
! 288: ($::steprc eq "SQLITE_ABORT" && $::column eq "198.198.198.198.198")
! 289: }
! 290: } {1}
! 291: do_test shared_ioerr-3rev.$n.cleanup.3 {
! 292: expr {
! 293: ($::steprc eq "SQLITE_ROW" && $::finalrc eq "SQLITE_OK") ||
! 294: ($::steprc eq "SQLITE_ERROR" && $::finalrc eq "SQLITE_IOERR") ||
! 295: ($::steprc eq "SQLITE_ERROR" && $::finalrc eq "SQLITE_ABORT")
! 296: }
! 297: } {1}
! 298:
! 299: # db2 eval {select * from sqlite_master}
! 300: db2 close
! 301: }
! 302:
! 303: # Provoke a malloc() failure when a cursor position is being saved. This
! 304: # only happens with index cursors (because they malloc() space to save the
! 305: # current key value). It does not happen with tables, because an integer
! 306: # key does not require a malloc() to store.
! 307: #
! 308: # The library should return an SQLITE_NOMEM to the caller. The query that
! 309: # owns the cursor (the one for which the position is not saved) should
! 310: # continue unaffected.
! 311: #
! 312: do_malloc_test shared_err-4 -tclprep {
! 313: sqlite3 db2 test.db
! 314: execsql {
! 315: PRAGMA read_uncommitted = 1;
! 316: BEGIN;
! 317: CREATE TABLE t1(a, b, UNIQUE(a, b));
! 318: } db2
! 319: for {set i 0} {$i < 5} {incr i} {
! 320: set a [string repeat $i 10]
! 321: set b [string repeat $i 2000]
! 322: execsql {INSERT INTO t1 VALUES($a, $b)} db2
! 323: }
! 324: execsql {COMMIT} db2
! 325: set ::DB2 [sqlite3_connection_pointer db2]
! 326: set ::STMT [sqlite3_prepare $::DB2 "SELECT a FROM t1 ORDER BY a" -1 DUMMY]
! 327: sqlite3_step $::STMT ;# Cursor points at 0000000000
! 328: sqlite3_step $::STMT ;# Cursor points at 1111111111
! 329: } -tclbody {
! 330: execsql {
! 331: INSERT INTO t1 VALUES(6, NULL);
! 332: }
! 333: } -cleanup {
! 334: do_test shared_malloc-4.$::n.cleanup.1 {
! 335: set ::rc [sqlite3_step $::STMT]
! 336: expr {$::rc=="SQLITE_ROW" || $::rc=="SQLITE_ERROR"}
! 337: } {1}
! 338: if {$::rc=="SQLITE_ROW"} {
! 339: do_test shared_malloc-4.$::n.cleanup.2 {
! 340: sqlite3_column_text $::STMT 0
! 341: } {2222222222}
! 342: }
! 343: do_test shared_malloc-4.$::n.cleanup.3 {
! 344: set rc [sqlite3_finalize $::STMT]
! 345: expr {$rc=="SQLITE_OK" || $rc=="SQLITE_ABORT" ||
! 346: $rc=="SQLITE_NOMEM" || $rc=="SQLITE_IOERR"}
! 347: } {1}
! 348: # db2 eval {select * from sqlite_master}
! 349: db2 close
! 350: }
! 351:
! 352: do_malloc_test shared_err-5 -tclbody {
! 353: db close
! 354: sqlite3 dbX test.db
! 355: sqlite3 dbY test.db
! 356: dbX close
! 357: dbY close
! 358: } -cleanup {
! 359: catch {dbX close}
! 360: catch {dbY close}
! 361: }
! 362:
! 363: do_malloc_test shared_err-6 -tclbody {
! 364: catch {db close}
! 365: ifcapable deprecated {
! 366: sqlite3_thread_cleanup
! 367: }
! 368: sqlite3_enable_shared_cache 0
! 369: } -cleanup {
! 370: sqlite3_enable_shared_cache 1
! 371: }
! 372:
! 373: # As of 3.5.0, sqlite3_enable_shared_cache can be called at
! 374: # any time and from any thread
! 375: #do_test shared_err-misuse-7.1 {
! 376: # sqlite3 db test.db
! 377: # catch {
! 378: # sqlite3_enable_shared_cache 0
! 379: # } msg
! 380: # set msg
! 381: #} {library routine called out of sequence}
! 382:
! 383: # Again provoke a malloc() failure when a cursor position is being saved,
! 384: # this time during a ROLLBACK operation by some other handle.
! 385: #
! 386: # The library should return an SQLITE_NOMEM to the caller. The query that
! 387: # owns the cursor (the one for which the position is not saved) should
! 388: # be aborted.
! 389: #
! 390: set ::aborted 0
! 391: do_malloc_test shared_err-8 -tclprep {
! 392: sqlite3 db2 test.db
! 393: execsql {
! 394: PRAGMA read_uncommitted = 1;
! 395: BEGIN;
! 396: CREATE TABLE t1(a, b, UNIQUE(a, b));
! 397: } db2
! 398: for {set i 0} {$i < 2} {incr i} {
! 399: set a [string repeat $i 10]
! 400: set b [string repeat $i 2000]
! 401: execsql {INSERT INTO t1 VALUES($a, $b)} db2
! 402: }
! 403: execsql {COMMIT} db2
! 404: set ::DB2 [sqlite3_connection_pointer db2]
! 405: set ::STMT [sqlite3_prepare $::DB2 "SELECT a FROM t1 ORDER BY a" -1 DUMMY]
! 406: sqlite3_step $::STMT ;# Cursor points at 0000000000
! 407: sqlite3_step $::STMT ;# Cursor points at 1111111111
! 408: } -tclbody {
! 409: execsql {
! 410: BEGIN;
! 411: INSERT INTO t1 VALUES(6, NULL);
! 412: ROLLBACK;
! 413: }
! 414: } -cleanup {
! 415: # UPDATE: As of [5668], if the rollback fails SQLITE_CORRUPT is returned.
! 416: # So these tests have been updated to expect SQLITE_CORRUPT and its
! 417: # associated English language error message.
! 418: #
! 419: do_test shared_malloc-8.$::n.cleanup.1 {
! 420: set res [catchsql {SELECT a FROM t1} db2]
! 421: set ans [lindex $res 1]
! 422: if {[lindex $res 0]} {
! 423: set r [expr {
! 424: $ans=="disk I/O error" ||
! 425: $ans=="out of memory" ||
! 426: $ans=="database disk image is malformed"
! 427: }]
! 428: } else {
! 429: set r [expr {[lrange $ans 0 1]=="0000000000 1111111111"}]
! 430: }
! 431: } {1}
! 432: do_test shared_malloc-8.$::n.cleanup.2 {
! 433: set rc1 [sqlite3_step $::STMT]
! 434: set rc2 [sqlite3_finalize $::STMT]
! 435: if {$rc2=="SQLITE_ABORT"} {
! 436: incr ::aborted
! 437: }
! 438: expr {
! 439: ($rc1=="SQLITE_DONE" && $rc2=="SQLITE_OK") ||
! 440: ($rc1=="SQLITE_ERROR" && $rc2=="SQLITE_ABORT") ||
! 441: ($rc1=="SQLITE_ERROR" && $rc2=="SQLITE_NOMEM") ||
! 442: ($rc1=="SQLITE_ERROR" && $rc2=="SQLITE_IOERR") ||
! 443: ($rc1=="SQLITE_ERROR" && $rc2=="SQLITE_CORRUPT")
! 444: }
! 445: } {1}
! 446: db2 close
! 447: }
! 448: do_test shared_malloc-8.X {
! 449: # Test that one or more queries were aborted due to the malloc() failure.
! 450: expr $::aborted>=1
! 451: } {1}
! 452:
! 453: # This test is designed to catch a specific bug that was present during
! 454: # development of 3.5.0. If a malloc() failed while setting the page-size,
! 455: # a buffer (Pager.pTmpSpace) was being freed. This could cause a seg-fault
! 456: # later if another connection tried to use the pager.
! 457: #
! 458: # This test will crash 3.4.2.
! 459: #
! 460: do_malloc_test shared_err-9 -tclprep {
! 461: sqlite3 db2 test.db
! 462: } -sqlbody {
! 463: PRAGMA page_size = 4096;
! 464: PRAGMA page_size = 1024;
! 465: } -cleanup {
! 466: db2 eval {
! 467: CREATE TABLE abc(a, b, c);
! 468: BEGIN;
! 469: INSERT INTO abc VALUES(1, 2, 3);
! 470: ROLLBACK;
! 471: }
! 472: db2 close
! 473: }
! 474:
! 475: catch {db close}
! 476: catch {db2 close}
! 477: do_malloc_test shared_err-10 -tclprep {
! 478: sqlite3 db test.db
! 479: sqlite3 db2 test.db
! 480:
! 481: db eval { SELECT * FROM sqlite_master }
! 482: db2 eval {
! 483: BEGIN;
! 484: CREATE TABLE abc(a, b, c);
! 485: }
! 486: } -tclbody {
! 487: catch {db eval {SELECT * FROM sqlite_master}}
! 488: error 1
! 489: } -cleanup {
! 490: execsql { SELECT * FROM sqlite_master }
! 491: }
! 492:
! 493: do_malloc_test shared_err-11 -tclprep {
! 494: sqlite3 db test.db
! 495: sqlite3 db2 test.db
! 496:
! 497: db eval { SELECT * FROM sqlite_master }
! 498: db2 eval {
! 499: BEGIN;
! 500: CREATE TABLE abc(a, b, c);
! 501: }
! 502: } -tclbody {
! 503: catch {db eval {SELECT * FROM sqlite_master}}
! 504: catch {sqlite3_errmsg16 db}
! 505: error 1
! 506: } -cleanup {
! 507: execsql { SELECT * FROM sqlite_master }
! 508: }
! 509:
! 510: catch {db close}
! 511: catch {db2 close}
! 512:
! 513: do_malloc_test shared_err-12 -sqlbody {
! 514: CREATE TABLE abc(a, b, c);
! 515: INSERT INTO abc VALUES(1, 2, 3);
! 516: }
! 517:
! 518: catch {db close}
! 519: catch {db2 close}
! 520: sqlite3_enable_shared_cache $::enable_shared_cache
! 521: finish_test
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>