Annotation of embedaddon/sqlite3/test/notify1.test, revision 1.1.1.1

1.1       misho       1: # 2009 March 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: # This file implements regression tests for SQLite library.  The
                     12: # focus of this file is testing the sqlite3_unlock_notify() API.
                     13: #
                     14: # $Id: notify1.test,v 1.4 2009/06/05 17:09:12 drh Exp $
                     15: 
                     16: set testdir [file dirname $argv0]
                     17: source $testdir/tester.tcl
                     18: 
                     19: ifcapable !unlock_notify||!shared_cache {
                     20:   finish_test
                     21:   return
                     22: }
                     23: db close
                     24: set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
                     25: 
                     26: #-------------------------------------------------------------------------
                     27: # Warm body test. Test that an unlock-notify callback can be registered 
                     28: # and that it is invoked.
                     29: #
                     30: do_test notify1-1.1 {
                     31:   sqlite3 db test.db
                     32:   sqlite3 db2 test.db
                     33:   execsql { CREATE TABLE t1(a, b) }
                     34: } {}
                     35: do_test notify1-1.2 {
                     36:   execsql {
                     37:     BEGIN;
                     38:     INSERT INTO t1 VALUES(1, 2);
                     39:   }
                     40:   catchsql { INSERT INTO t1 VALUES(3, 4) } db2
                     41: } {1 {database table is locked}}
                     42: do_test notify1-1.3 {
                     43:   set zScript ""
                     44:   db2 unlock_notify {
                     45:     set zScript "db2 eval { INSERT INTO t1 VALUES(3, 4) }"
                     46:   }
                     47:   execsql { SELECT * FROM t1 }
                     48: } {1 2}
                     49: do_test notify1-1.4 {
                     50:   set zScript
                     51: } {}
                     52: do_test notify1-1.5 {
                     53:   execsql { COMMIT }
                     54:   eval $zScript
                     55:   execsql { SELECT * FROM t1 }
                     56: } {1 2 3 4}
                     57: 
                     58: #-------------------------------------------------------------------------
                     59: # Verify that invoking the "unlock_notify" method with no arguments
                     60: # (which is the equivalent of invoking sqlite3_unlock_notify() with
                     61: # a NULL xNotify argument) cancels a pending notify callback.
                     62: #
                     63: do_test notify1-1.11 {
                     64:   execsql { DROP TABLE t1; CREATE TABLE t1(a, b) }
                     65: } {}
                     66: do_test notify1-1.12 {
                     67:   execsql {
                     68:     BEGIN;
                     69:     INSERT INTO t1 VALUES(1, 2);
                     70:   }
                     71:   catchsql { INSERT INTO t1 VALUES(3, 4) } db2
                     72: } {1 {database table is locked}}
                     73: do_test notify1-1.13 {
                     74:   set zScript ""
                     75:   db2 unlock_notify {
                     76:     set zScript "db2 eval { INSERT INTO t1 VALUES(3, 4) }"
                     77:   }
                     78:   execsql { SELECT * FROM t1 }
                     79: } {1 2}
                     80: do_test notify1-1.14 {
                     81:   set zScript
                     82: } {}
                     83: do_test notify1-1.15 {
                     84:   db2 unlock_notify
                     85:   execsql { COMMIT }
                     86:   eval $zScript
                     87:   execsql { SELECT * FROM t1 }
                     88: } {1 2}
                     89: 
                     90: #-------------------------------------------------------------------------
                     91: # The following tests, notify1-2.*, test that deadlock is detected 
                     92: # correctly.
                     93: # 
                     94: do_test notify1-2.1 {
                     95:   execsql { 
                     96:     CREATE TABLE t2(a, b);
                     97:     INSERT INTO t2 VALUES('I', 'II');
                     98:   }
                     99: } {}
                    100: 
                    101: #
                    102: # Test for simple deadlock involving two database connections.
                    103: #
                    104: # 1. Grab a write-lock on t1 with [db]. Then grab a read-lock on t2 with [db2].
                    105: # 2. Try to grab a read-lock on t1 with [db2] (fails).
                    106: # 3. Have [db2] wait on the read-lock it failed to obtain in step 2.
                    107: # 4. Try to grab a write-lock on t2 with [db] (fails).
                    108: # 5. Try to have [db] wait on the lock from step 4. Fails, as the system
                    109: #    would be deadlocked (since [db2] is already waiting on [db], and this
                    110: #    operation would have [db] wait on [db2]).
                    111: #
                    112: do_test notify1-2.2.1 {
                    113:   execsql {
                    114:     BEGIN;
                    115:     INSERT INTO t1 VALUES(5, 6);
                    116:   }
                    117:   execsql {
                    118:     BEGIN;
                    119:     SELECT * FROM t2;
                    120:   } db2
                    121: } {I II}
                    122: do_test notify1-2.2.2 {
                    123:   catchsql { SELECT * FROM t1 } db2
                    124: } {1 {database table is locked: t1}}
                    125: do_test notify1-2.2.3 {
                    126:   db2 unlock_notify {lappend unlock_notify db2}
                    127: } {}
                    128: do_test notify1-2.2.4 {
                    129:   catchsql { INSERT INTO t2 VALUES('III', 'IV') }
                    130: } {1 {database table is locked: t2}}
                    131: do_test notify1-2.2.5 {
                    132:   set rc [catch { db unlock_notify {lappend unlock_notify db} } msg]
                    133:   list $rc $msg
                    134: } {1 {database is deadlocked}}
                    135: 
                    136: #
                    137: # Test for slightly more complex deadlock involving three database
                    138: # connections: db, db2 and db3.
                    139: #
                    140: do_test notify1-2.3.1 {
                    141:   db close
                    142:   db2 close
                    143:   forcedelete test.db test2.db test3.db
                    144:   foreach con {db db2 db3} {
                    145:     sqlite3 $con test.db
                    146:     $con eval { ATTACH 'test2.db' AS aux2 }
                    147:     $con eval { ATTACH 'test3.db' AS aux3 }
                    148:   }
                    149:   execsql {
                    150:     CREATE TABLE main.t1(a, b);
                    151:     CREATE TABLE aux2.t2(a, b);
                    152:     CREATE TABLE aux3.t3(a, b);
                    153:   }
                    154: } {}
                    155: do_test notify1-2.3.2 {
                    156:   execsql { BEGIN ; INSERT INTO t1 VALUES(1, 2) } db
                    157:   execsql { BEGIN ; INSERT INTO t2 VALUES(1, 2) } db2
                    158:   execsql { BEGIN ; INSERT INTO t3 VALUES(1, 2) } db3
                    159: } {}
                    160: do_test notify1-2.3.3 {
                    161:   catchsql { SELECT * FROM t2 } db
                    162: } {1 {database table is locked: t2}}
                    163: do_test notify1-2.3.4 {
                    164:   catchsql { SELECT * FROM t3 } db2
                    165: } {1 {database table is locked: t3}}
                    166: do_test notify1-2.3.5 {
                    167:   catchsql { SELECT * FROM t1 } db3
                    168: } {1 {database table is locked: t1}}
                    169: do_test notify1-2.3.6 {
                    170:   set lUnlock [list]
                    171:   db  unlock_notify {lappend lUnlock db}
                    172:   db2 unlock_notify {lappend lUnlock db2}
                    173: } {}
                    174: do_test notify1-2.3.7 {
                    175:   set rc [catch { db3 unlock_notify {lappend lUnlock db3} } msg]
                    176:   list $rc $msg
                    177: } {1 {database is deadlocked}}
                    178: do_test notify1-2.3.8 {
                    179:   execsql { COMMIT }
                    180:   set lUnlock
                    181: } {}
                    182: do_test notify1-2.3.9 {
                    183:   db3 unlock_notify {lappend lUnlock db3} 
                    184:   set lUnlock
                    185: } {db3}
                    186: do_test notify1-2.3.10 {
                    187:   execsql { COMMIT } db2
                    188:   set lUnlock
                    189: } {db3 db}
                    190: do_test notify1-2.3.11 {
                    191:   execsql { COMMIT } db3
                    192:   set lUnlock
                    193: } {db3 db db2}
                    194: catch { db3 close }
                    195: catch { db2 close }
                    196: catch { db close }
                    197: 
                    198: #-------------------------------------------------------------------------
                    199: # The following tests, notify1-3.* and notify1-4.*, test that callbacks 
                    200: # can be issued when there are many (>16) connections waiting on a single 
                    201: # unlock event.
                    202: # 
                    203: foreach {tn nConn} {3 20 4 76} {
                    204:   do_test notify1-$tn.1 {
                    205:     sqlite3 db test.db
                    206:     execsql {
                    207:       BEGIN;
                    208:       INSERT INTO t1 VALUES('a', 'b');
                    209:     }
                    210:   } {}
                    211:   set lUnlock [list]
                    212:   set lUnlockFinal [list]
                    213:   for {set ii 1} {$ii <= $nConn} {incr ii} {
                    214:     do_test notify1-$tn.2.$ii.1 {
                    215:       set cmd "db$ii"
                    216:       sqlite3 $cmd test.db
                    217:       catchsql { SELECT * FROM t1 } $cmd
                    218:     } {1 {database table is locked: t1}}
                    219:     do_test notify1-$tn.2.$ii.2 {
                    220:       $cmd unlock_notify "lappend lUnlock $ii"
                    221:     } {}
                    222:     lappend lUnlockFinal $ii
                    223:   }
                    224:   do_test notify1-$tn.3 {
                    225:     set lUnlock
                    226:   } {}
                    227:   do_test notify1-$tn.4 {
                    228:     execsql {COMMIT}
                    229:     lsort -integer $lUnlock
                    230:   } $lUnlockFinal
                    231:   do_test notify1-$tn.5 {
                    232:     for {set ii 1} {$ii <= $nConn} {incr ii} {
                    233:       "db$ii" close
                    234:     }
                    235:   } {}
                    236: }
                    237: db close
                    238: 
                    239: #-------------------------------------------------------------------------
                    240: # These tests, notify1-5.*, test that a malloc() failure that occurs while
                    241: # allocating an array to use as an argument to an unlock-notify callback
                    242: # is handled correctly.
                    243: # 
                    244: source $testdir/malloc_common.tcl
                    245: do_malloc_test notify1-5 -tclprep {
                    246:   set ::lUnlock [list]
                    247:   execsql {
                    248:     CREATE TABLE t1(a, b);
                    249:     BEGIN;
                    250:     INSERT INTO t1 VALUES('a', 'b');
                    251:   }
                    252:   for {set ii 1} {$ii <= 60} {incr ii} {
                    253:     set cmd "db$ii"
                    254:     sqlite3 $cmd test.db
                    255:     catchsql { SELECT * FROM t1 } $cmd
                    256:     $cmd unlock_notify "lappend ::lUnlock $ii"
                    257:   }
                    258: } -sqlbody {
                    259:   COMMIT;
                    260: } -cleanup {
                    261:   # One of two things should have happened:
                    262:   #
                    263:   #   1) The transaction opened by [db] was not committed. No unlock-notify
                    264:   #      callbacks were invoked, OR
                    265:   #   2) The transaction opened by [db] was committed and 60 unlock-notify
                    266:   #      callbacks were invoked.
                    267:   #
                    268:   do_test notify1-5.systemstate {
                    269:     expr { ([llength $::lUnlock]==0 && [sqlite3_get_autocommit db]==0)
                    270:         || ([llength $::lUnlock]==60 && [sqlite3_get_autocommit db]==1)
                    271:     }
                    272:   } {1}
                    273:   for {set ii 1} {$ii <= 60} {incr ii} { "db$ii" close }
                    274: }
                    275: 
                    276: #-------------------------------------------------------------------------
                    277: # Test cases notify1-6.* test cases where the following occur:
                    278: # 
                    279: #   notify1-6.1.*: Test encountering an SQLITE_LOCKED error when the
                    280: #                  "blocking connection" has already been set by a previous
                    281: #                  SQLITE_LOCKED.
                    282: #
                    283: #   notify1-6.2.*: Test encountering an SQLITE_LOCKED error when already
                    284: #                  waiting on an unlock-notify callback.
                    285: #
                    286: #   notify1-6.3.*: Test that if an SQLITE_LOCKED error is encountered while
                    287: #                  already waiting on an unlock-notify callback, and then
                    288: #                  the blocker that caused the SQLITE_LOCKED commits its
                    289: #                  transaction, the unlock-notify callback is not invoked.
                    290: #
                    291: #   notify1-6.4.*: Like 6.3.*, except that instead of the second blocker
                    292: #                  committing its transaction, the first does. The 
                    293: #                  unlock-notify callback is therefore invoked.
                    294: #
                    295: db close
                    296: do_test notify1-6.1.1 {
                    297:   forcedelete test.db test2.db
                    298:   foreach conn {db db2 db3} {
                    299:     sqlite3 $conn test.db
                    300:     execsql { ATTACH 'test2.db' AS two } $conn
                    301:   }
                    302:   execsql {
                    303:     CREATE TABLE t1(a, b);
                    304:     CREATE TABLE two.t2(a, b);
                    305:   }
                    306:   execsql { 
                    307:     BEGIN;
                    308:     INSERT INTO t1 VALUES(1, 2);
                    309:   } db2
                    310:   execsql { 
                    311:     BEGIN;
                    312:     INSERT INTO t2 VALUES(1, 2);
                    313:   } db3
                    314: } {}
                    315: do_test notify1-6.1.2 {
                    316:   catchsql { SELECT * FROM t2 }
                    317: } {1 {database table is locked: t2}}
                    318: do_test notify1-6.1.3 {
                    319:   catchsql { SELECT * FROM t1 }
                    320: } {1 {database table is locked: t1}}
                    321: 
                    322: do_test notify1-6.2.1 {
                    323:   set unlocked 0
                    324:   db unlock_notify {set unlocked 1}
                    325:   set unlocked
                    326: } {0}
                    327: do_test notify1-6.2.2 {
                    328:   catchsql { SELECT * FROM t2 }
                    329: } {1 {database table is locked: t2}}
                    330: do_test notify1-6.2.3 {
                    331:   execsql { COMMIT } db2
                    332:   set unlocked
                    333: } {1}
                    334: 
                    335: do_test notify1-6.3.1 {
                    336:   execsql { 
                    337:     BEGIN;
                    338:     INSERT INTO t1 VALUES(3, 4);
                    339:   } db2
                    340: } {}
                    341: do_test notify1-6.3.2 {
                    342:   catchsql { SELECT * FROM t1 }
                    343: } {1 {database table is locked: t1}}
                    344: do_test notify1-6.3.3 {
                    345:   set unlocked 0
                    346:   db unlock_notify {set unlocked 1}
                    347:   set unlocked
                    348: } {0}
                    349: do_test notify1-6.3.4 {
                    350:   catchsql { SELECT * FROM t2 }
                    351: } {1 {database table is locked: t2}}
                    352: do_test notify1-6.3.5 {
                    353:   execsql { COMMIT } db3
                    354:   set unlocked
                    355: } {0}
                    356: 
                    357: do_test notify1-6.4.1 {
                    358:   execsql { 
                    359:     BEGIN;
                    360:     INSERT INTO t2 VALUES(3, 4);
                    361:   } db3
                    362:   catchsql { SELECT * FROM t2 }
                    363: } {1 {database table is locked: t2}}
                    364: do_test notify1-6.4.2 {
                    365:   execsql { COMMIT } db2
                    366:   set unlocked
                    367: } {1}
                    368: do_test notify1-6.4.3 {
                    369:   execsql { COMMIT } db3
                    370: } {}
                    371: db close
                    372: db2 close
                    373: db3 close
                    374: 
                    375: #-------------------------------------------------------------------------
                    376: # Test cases notify1-7.* tests that when more than one distinct 
                    377: # unlock-notify function is registered, all are invoked correctly.
                    378: #
                    379: proc unlock_notify {} {
                    380:   incr ::unlock_notify
                    381: }
                    382: do_test notify1-7.1 {
                    383:   foreach conn {db db2 db3} {
                    384:     sqlite3 $conn test.db
                    385:   }
                    386:   execsql {
                    387:     BEGIN;
                    388:     INSERT INTO t1 VALUES(5, 6);
                    389:   }
                    390: } {}
                    391: do_test notify1-7.2 {
                    392:   catchsql { SELECT * FROM t1 } db2
                    393: } {1 {database table is locked: t1}}
                    394: do_test notify1-7.3 {
                    395:   catchsql { SELECT * FROM t1 } db3
                    396: } {1 {database table is locked: t1}}
                    397: do_test notify1-7.4 {
                    398:   set unlock_notify 0
                    399:   db2 unlock_notify unlock_notify
                    400:   sqlite3_unlock_notify db3
                    401: } {SQLITE_OK}
                    402: do_test notify1-7.5 {
                    403:   set unlock_notify
                    404: } {0}
                    405: do_test notify1-7.6 {
                    406:   execsql { COMMIT }
                    407:   set unlock_notify
                    408: } {2}
                    409: 
                    410: #-------------------------------------------------------------------------
                    411: # Test cases notify1-8.* tests that the correct SQLITE_LOCKED extended 
                    412: # error code is returned in various scenarios.
                    413: #
                    414: do_test notify1-8.1 {
                    415:   execsql {
                    416:     BEGIN;
                    417:     INSERT INTO t1 VALUES(7, 8);
                    418:   }
                    419:   catchsql { SELECT * FROM t1 } db2
                    420: } {1 {database table is locked: t1}}
                    421: do_test notify1-8.2 {
                    422:   sqlite3_extended_errcode db2
                    423: } {SQLITE_LOCKED_SHAREDCACHE}
                    424: 
                    425: do_test notify1-8.3 {
                    426:   execsql {
                    427:     COMMIT;
                    428:     BEGIN EXCLUSIVE;
                    429:   }
                    430:   catchsql { SELECT * FROM t1 } db2
                    431: } {1 {database schema is locked: main}}
                    432: do_test notify1-8.4 {
                    433:   sqlite3_extended_errcode db2
                    434: } {SQLITE_LOCKED_SHAREDCACHE}
                    435: 
                    436: do_test notify1-8.X {
                    437:   execsql { COMMIT } 
                    438: } {}
                    439: 
                    440: #-------------------------------------------------------------------------
                    441: # Test cases notify1-9.* test the shared-cache 'pending-lock' feature.
                    442: #
                    443: do_test notify1-9.1 {
                    444:   execsql {
                    445:     CREATE TABLE t2(a, b);
                    446:     BEGIN;
                    447:     SELECT * FROM t1;
                    448:   } db2
                    449: } {1 2 3 4 5 6 7 8}
                    450: do_test notify1-9.2 {
                    451:   execsql { SELECT * FROM t1 } db3
                    452: } {1 2 3 4 5 6 7 8}
                    453: do_test notify1-9.3 {
                    454:   catchsql { 
                    455:     BEGIN;
                    456:     INSERT INTO t1 VALUES(9, 10);
                    457:   }
                    458: } {1 {database table is locked: t1}}
                    459: do_test notify1-9.4 {
                    460:   catchsql { SELECT * FROM t2 } db3
                    461: } {1 {database table is locked}}
                    462: do_test notify1-9.5 {
                    463:   execsql  { COMMIT } db2
                    464:   execsql { SELECT * FROM t2 } db3
                    465: } {}
                    466: do_test notify1-9.6 {
                    467:   execsql  { COMMIT }
                    468: } {}
                    469: 
                    470: do_test notify1-9.7 {
                    471:   execsql {
                    472:     BEGIN;
                    473:     SELECT * FROM t1;
                    474:   } db2
                    475: } {1 2 3 4 5 6 7 8}
                    476: do_test notify1-9.8 {
                    477:   execsql { SELECT * FROM t1 } db3
                    478: } {1 2 3 4 5 6 7 8}
                    479: do_test notify1-9.9 {
                    480:   catchsql { 
                    481:     BEGIN;
                    482:     INSERT INTO t1 VALUES(9, 10);
                    483:   }
                    484: } {1 {database table is locked: t1}}
                    485: do_test notify1-9.10 {
                    486:   catchsql { SELECT * FROM t2 } db3
                    487: } {1 {database table is locked}}
                    488: do_test notify1-9.11 {
                    489:   execsql  { COMMIT }
                    490:   execsql { SELECT * FROM t2 } db3
                    491: } {}
                    492: do_test notify1-9.12 {
                    493:   execsql  { COMMIT } db2
                    494: } {}
                    495: 
                    496: db close
                    497: db2 close
                    498: db3 close
                    499: sqlite3_enable_shared_cache $::enable_shared_cache
                    500: finish_test

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>