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

1.1       misho       1: # 2001 September 15
                      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 script is database locks.
                     13: #
                     14: # $Id: lock.test,v 1.40 2009/06/16 17:49:36 drh Exp $
                     15: 
                     16: 
                     17: set testdir [file dirname $argv0]
                     18: source $testdir/tester.tcl
                     19: 
                     20: # Create an alternative connection to the database
                     21: #
                     22: do_test lock-1.0 {
                     23:   # Give a complex pathname to stress the path simplification logic in
                     24:   # the vxworks driver and in test_async.
                     25:   file mkdir tempdir/t1/t2
                     26:   sqlite3 db2 ./tempdir/../tempdir/t1/.//t2/../../..//test.db
                     27:   set dummy {}
                     28: } {}
                     29: do_test lock-1.1 {
                     30:   execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
                     31: } {}
                     32: do_test lock-1.2 {
                     33:   execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name} db2
                     34: } {}
                     35: do_test lock-1.3 {
                     36:   execsql {CREATE TABLE t1(a int, b int)}
                     37:   execsql {SELECT name FROM sqlite_master WHERE type='table' ORDER BY name}
                     38: } {t1}
                     39: do_test lock-1.5 {
                     40:   catchsql {
                     41:      SELECT name FROM sqlite_master WHERE type='table' ORDER BY name
                     42:   } db2
                     43: } {0 t1}
                     44: 
                     45: do_test lock-1.6 {
                     46:   execsql {INSERT INTO t1 VALUES(1,2)}
                     47:   execsql {SELECT * FROM t1}
                     48: } {1 2}
                     49: # Update: The schema is now brought up to date by test lock-1.5.
                     50: # do_test lock-1.7.1 {
                     51: #   catchsql {SELECT * FROM t1} db2
                     52: # } {1 {no such table: t1}}
                     53: do_test lock-1.7.2 {
                     54:   catchsql {SELECT * FROM t1} db2
                     55: } {0 {1 2}}
                     56: do_test lock-1.8 {
                     57:   execsql {UPDATE t1 SET a=b, b=a} db2
                     58:   execsql {SELECT * FROM t1} db2
                     59: } {2 1}
                     60: do_test lock-1.9 {
                     61:   execsql {SELECT * FROM t1}
                     62: } {2 1}
                     63: do_test lock-1.10 {
                     64:   execsql {BEGIN TRANSACTION}
                     65:   execsql {UPDATE t1 SET a = 0 WHERE 0}
                     66:   execsql {SELECT * FROM t1}
                     67: } {2 1}
                     68: do_test lock-1.11 {
                     69:   catchsql {SELECT * FROM t1} db2
                     70: } {0 {2 1}}
                     71: do_test lock-1.12 {
                     72:   execsql {ROLLBACK}
                     73:   catchsql {SELECT * FROM t1}
                     74: } {0 {2 1}}
                     75: 
                     76: do_test lock-1.13 {
                     77:   execsql {CREATE TABLE t2(x int, y int)}
                     78:   execsql {INSERT INTO t2 VALUES(8,9)}
                     79:   execsql {SELECT * FROM t2}
                     80: } {8 9}
                     81: do_test lock-1.14.1 {
                     82:   catchsql {SELECT * FROM t2} db2
                     83: } {0 {8 9}}
                     84: do_test lock-1.14.2 {
                     85:   catchsql {SELECT * FROM t1} db2
                     86: } {0 {2 1}}
                     87: do_test lock-1.15 {
                     88:   catchsql {SELECT * FROM t2} db2
                     89: } {0 {8 9}}
                     90: 
                     91: do_test lock-1.16 {
                     92:   db eval {SELECT * FROM t1} qv {
                     93:     set x [db eval {SELECT * FROM t1}]
                     94:   }
                     95:   set x
                     96: } {2 1}
                     97: do_test lock-1.17 {
                     98:   db eval {SELECT * FROM t1} qv {
                     99:     set x [db eval {SELECT * FROM t2}]
                    100:   }
                    101:   set x
                    102: } {8 9}
                    103: 
                    104: # You cannot UPDATE a table from within the callback of a SELECT
                    105: # on that same table because the SELECT has the table locked.
                    106: #
                    107: # 2006-08-16:  Reads no longer block writes within the same
                    108: # database connection.
                    109: #
                    110: #do_test lock-1.18 {
                    111: #  db eval {SELECT * FROM t1} qv {
                    112: #    set r [catch {db eval {UPDATE t1 SET a=b, b=a}} msg]
                    113: #    lappend r $msg
                    114: #  }
                    115: #  set r
                    116: #} {1 {database table is locked}}
                    117: 
                    118: # But you can UPDATE a different table from the one that is used in
                    119: # the SELECT.
                    120: #
                    121: do_test lock-1.19 {
                    122:   db eval {SELECT * FROM t1} qv {
                    123:     set r [catch {db eval {UPDATE t2 SET x=y, y=x}} msg]
                    124:     lappend r $msg
                    125:   }
                    126:   set r
                    127: } {0 {}}
                    128: do_test lock-1.20 {
                    129:   execsql {SELECT * FROM t2}
                    130: } {9 8}
                    131: 
                    132: # It is possible to do a SELECT of the same table within the
                    133: # callback of another SELECT on that same table because two
                    134: # or more read-only cursors can be open at once.
                    135: #
                    136: do_test lock-1.21 {
                    137:   db eval {SELECT * FROM t1} qv {
                    138:     set r [catch {db eval {SELECT a FROM t1}} msg]
                    139:     lappend r $msg
                    140:   }
                    141:   set r
                    142: } {0 2}
                    143: 
                    144: # Under UNIX you can do two SELECTs at once with different database
                    145: # connections, because UNIX supports reader/writer locks.  Under windows,
                    146: # this is not possible.
                    147: #
                    148: if {$::tcl_platform(platform)=="unix"} {
                    149:   do_test lock-1.22 {
                    150:     db eval {SELECT * FROM t1} qv {
                    151:       set r [catch {db2 eval {SELECT a FROM t1}} msg]
                    152:       lappend r $msg
                    153:     }
                    154:     set r
                    155:   } {0 2}
                    156: }
                    157: integrity_check lock-1.23
                    158: 
                    159: # If one thread has a transaction another thread cannot start
                    160: # a transaction.  -> Not true in version 3.0.  But if one thread
                    161: # as a RESERVED lock another thread cannot acquire one.
                    162: #
                    163: do_test lock-2.1 {
                    164:   execsql {BEGIN TRANSACTION}
                    165:   execsql {UPDATE t1 SET a = 0 WHERE 0}
                    166:   execsql {BEGIN TRANSACTION} db2
                    167:   set r [catch {execsql {UPDATE t1 SET a = 0 WHERE 0} db2} msg]
                    168:   execsql {ROLLBACK} db2
                    169:   lappend r $msg
                    170: } {1 {database is locked}}
                    171: 
                    172: # A thread can read when another has a RESERVED lock.
                    173: #
                    174: do_test lock-2.2 {
                    175:   catchsql {SELECT * FROM t2} db2
                    176: } {0 {9 8}}
                    177: 
                    178: # If the other thread (the one that does not hold the transaction with
                    179: # a RESERVED lock) tries to get a RESERVED lock, we do get a busy callback
                    180: # as long as we were not orginally holding a READ lock.
                    181: #
                    182: do_test lock-2.3.1 {
                    183:   proc callback {count} {
                    184:     set ::callback_value $count
                    185:     break
                    186:   }
                    187:   set ::callback_value {}
                    188:   db2 busy callback
                    189:   # db2 does not hold a lock so we should get a busy callback here
                    190:   set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg]
                    191:   lappend r $msg
                    192:   lappend r $::callback_value
                    193: } {1 {database is locked} 0}
                    194: do_test lock-2.3.2 {
                    195:   set ::callback_value {}
                    196:   execsql {BEGIN; SELECT rowid FROM sqlite_master LIMIT 1} db2
                    197:   # This time db2 does hold a read lock.  No busy callback this time.
                    198:   set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg]
                    199:   lappend r $msg
                    200:   lappend r $::callback_value
                    201: } {1 {database is locked} {}}
                    202: catch {execsql {ROLLBACK} db2}
                    203: do_test lock-2.4.1 {
                    204:   proc callback {count} {
                    205:     lappend ::callback_value $count
                    206:     if {$count>4} break
                    207:   }
                    208:   set ::callback_value {}
                    209:   db2 busy callback
                    210:   # We get a busy callback because db2 is not holding a lock
                    211:   set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg]
                    212:   lappend r $msg
                    213:   lappend r $::callback_value
                    214: } {1 {database is locked} {0 1 2 3 4 5}}
                    215: do_test lock-2.4.2 {
                    216:   proc callback {count} {
                    217:     lappend ::callback_value $count
                    218:     if {$count>4} break
                    219:   }
                    220:   set ::callback_value {}
                    221:   db2 busy callback
                    222:   execsql {BEGIN; SELECT rowid FROM sqlite_master LIMIT 1} db2
                    223:   # No busy callback this time because we are holding a lock
                    224:   set r [catch {execsql {UPDATE t1 SET a=b, b=a} db2} msg]
                    225:   lappend r $msg
                    226:   lappend r $::callback_value
                    227: } {1 {database is locked} {}}
                    228: catch {execsql {ROLLBACK} db2}
                    229: do_test lock-2.5 {
                    230:   proc callback {count} {
                    231:     lappend ::callback_value $count
                    232:     if {$count>4} break
                    233:   }
                    234:   set ::callback_value {}
                    235:   db2 busy callback
                    236:   set r [catch {execsql {SELECT * FROM t1} db2} msg]
                    237:   lappend r $msg
                    238:   lappend r $::callback_value
                    239: } {0 {2 1} {}}
                    240: execsql {ROLLBACK}
                    241: 
                    242: # Test the built-in busy timeout handler
                    243: #
                    244: do_test lock-2.8 {
                    245:   db2 timeout 400
                    246:   execsql BEGIN
                    247:   execsql {UPDATE t1 SET a = 0 WHERE 0}
                    248:   catchsql {BEGIN EXCLUSIVE;} db2
                    249: } {1 {database is locked}}
                    250: do_test lock-2.9 {
                    251:   db2 timeout 0
                    252:   execsql COMMIT
                    253: } {}
                    254: integrity_check lock-2.10
                    255: 
                    256: # Try to start two transactions in a row
                    257: #
                    258: do_test lock-3.1 {
                    259:   execsql {BEGIN TRANSACTION}
                    260:   set r [catch {execsql {BEGIN TRANSACTION}} msg]
                    261:   execsql {ROLLBACK}
                    262:   lappend r $msg
                    263: } {1 {cannot start a transaction within a transaction}}
                    264: integrity_check lock-3.2
                    265: 
                    266: # Make sure the busy handler and error messages work when
                    267: # opening a new pointer to the database while another pointer
                    268: # has the database locked.
                    269: #
                    270: do_test lock-4.1 {
                    271:   db2 close
                    272:   catch {db eval ROLLBACK}
                    273:   db eval BEGIN
                    274:   db eval {UPDATE t1 SET a=0 WHERE 0}
                    275:   sqlite3 db2 ./test.db
                    276:   catchsql {UPDATE t1 SET a=0} db2
                    277: } {1 {database is locked}}
                    278: do_test lock-4.2 {
                    279:   set ::callback_value {}
                    280:   set rc [catch {db2 eval {UPDATE t1 SET a=0}} msg]
                    281:   lappend rc $msg $::callback_value
                    282: } {1 {database is locked} {}}
                    283: do_test lock-4.3 {
                    284:   proc callback {count} {
                    285:     lappend ::callback_value $count
                    286:     if {$count>4} break
                    287:   }
                    288:   db2 busy callback
                    289:   set rc [catch {db2 eval {UPDATE t1 SET a=0}} msg]
                    290:   lappend rc $msg $::callback_value
                    291: } {1 {database is locked} {0 1 2 3 4 5}}
                    292: execsql {ROLLBACK}
                    293: 
                    294: # When one thread is writing, other threads cannot read.  Except if the
                    295: # writing thread is writing to its temporary tables, the other threads
                    296: # can still read.  -> Not so in 3.0.  One thread can read while another
                    297: # holds a RESERVED lock.
                    298: #
                    299: proc tx_exec {sql} {
                    300:   db2 eval $sql
                    301: }
                    302: do_test lock-5.1 {
                    303:   execsql {
                    304:     SELECT * FROM t1
                    305:   }
                    306: } {2 1}
                    307: do_test lock-5.2 {
                    308:   db function tx_exec tx_exec
                    309:   catchsql {
                    310:     INSERT INTO t1(a,b) SELECT 3, tx_exec('SELECT y FROM t2 LIMIT 1');
                    311:   }
                    312: } {0 {}}
                    313: 
                    314: ifcapable tempdb {
                    315:   do_test lock-5.3 {
                    316:     execsql {
                    317:       CREATE TEMP TABLE t3(x);
                    318:       SELECT * FROM t3;
                    319:     }
                    320:   } {}
                    321:   do_test lock-5.4 {
                    322:     catchsql {
                    323:       INSERT INTO t3 SELECT tx_exec('SELECT y FROM t2 LIMIT 1');
                    324:     }
                    325:   } {0 {}}
                    326:   do_test lock-5.5 {
                    327:     execsql {
                    328:       SELECT * FROM t3;
                    329:     }
                    330:   } {8}
                    331:   do_test lock-5.6 {
                    332:     catchsql {
                    333:       UPDATE t1 SET a=tx_exec('SELECT x FROM t2');
                    334:     }
                    335:   } {0 {}}
                    336:   do_test lock-5.7 {
                    337:     execsql {
                    338:       SELECT * FROM t1;
                    339:     }
                    340:   } {9 1 9 8}
                    341:   do_test lock-5.8 {
                    342:     catchsql {
                    343:       UPDATE t3 SET x=tx_exec('SELECT x FROM t2');
                    344:     }
                    345:   } {0 {}}
                    346:   do_test lock-5.9 {
                    347:     execsql {
                    348:       SELECT * FROM t3;
                    349:     }
                    350:   } {9}
                    351: }
                    352: 
                    353: do_test lock-6.1 {
                    354:   execsql {
                    355:     CREATE TABLE t4(a PRIMARY KEY, b);
                    356:     INSERT INTO t4 VALUES(1, 'one');
                    357:     INSERT INTO t4 VALUES(2, 'two');
                    358:     INSERT INTO t4 VALUES(3, 'three');
                    359:   }
                    360: 
                    361:   set STMT [sqlite3_prepare $DB "SELECT * FROM sqlite_master" -1 TAIL]
                    362:   sqlite3_step $STMT
                    363: 
                    364:   execsql { DELETE FROM t4 }
                    365:   execsql { SELECT * FROM sqlite_master } db2
                    366:   execsql { SELECT * FROM t4 } db2
                    367: } {}
                    368: 
                    369: do_test lock-6.2 {
                    370:   execsql { 
                    371:     BEGIN;
                    372:     INSERT INTO t4 VALUES(1, 'one');
                    373:     INSERT INTO t4 VALUES(2, 'two');
                    374:     INSERT INTO t4 VALUES(3, 'three');
                    375:     COMMIT;
                    376:   }
                    377: 
                    378:   execsql { SELECT * FROM t4 } db2
                    379: } {1 one 2 two 3 three}
                    380: 
                    381: do_test lock-6.3 {
                    382:   execsql { SELECT a FROM t4 ORDER BY a } db2
                    383: } {1 2 3}
                    384: 
                    385: do_test lock-6.4 {
                    386:   execsql { PRAGMA integrity_check } db2
                    387: } {ok}
                    388: 
                    389: do_test lock-6.5 {
                    390:   sqlite3_finalize $STMT
                    391: } {SQLITE_OK}
                    392: 
                    393: # At one point the following set of conditions would cause SQLite to 
                    394: # retain a RESERVED or EXCLUSIVE lock after the transaction was committed:
                    395: # 
                    396: #   * The journal-mode is set to something other than 'delete', and
                    397: #   * there exists one or more active read-only statements, and
                    398: #   * a transaction that modified zero database pages is committed.
                    399: # 
                    400: set temp_status unlocked
                    401: if {$TEMP_STORE>=2} {set temp_status unknown}
                    402: do_test lock-7.1 {
                    403:   set STMT [sqlite3_prepare $DB "SELECT * FROM sqlite_master" -1 TAIL]
                    404:   sqlite3_step $STMT
                    405: } {SQLITE_ROW}
                    406: do_test lock-7.2 {
                    407:   execsql { PRAGMA lock_status }
                    408: } [list main shared temp $temp_status]
                    409: do_test lock-7.3 {
                    410:   execsql {
                    411:     PRAGMA journal_mode = truncate;
                    412:     BEGIN;
                    413:     UPDATE t4 SET a = 10 WHERE 0;
                    414:     COMMIT;
                    415:   }
                    416:   execsql { PRAGMA lock_status }
                    417: } [list main shared temp $temp_status]
                    418: do_test lock-7.4 {
                    419:   sqlite3_finalize $STMT
                    420: } {SQLITE_OK}
                    421: 
                    422: do_test lock-999.1 {
                    423:   rename db2 {}
                    424: } {}
                    425: 
                    426: finish_test

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