Annotation of embedaddon/sqlite3/test/shared.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: # $Id: shared.test,v 1.36 2009/03/16 13:19:36 danielk1977 Exp $
        !            13: 
        !            14: set testdir [file dirname $argv0]
        !            15: source $testdir/tester.tcl
        !            16: db close
        !            17: 
        !            18: # These tests cannot be run without the ATTACH command.
        !            19: #
        !            20: ifcapable !shared_cache||!attach {
        !            21:   finish_test
        !            22:   return
        !            23: }
        !            24: 
        !            25: set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
        !            26: 
        !            27: foreach av [list 0 1] {
        !            28: 
        !            29: # Open the database connection and execute the auto-vacuum pragma
        !            30: forcedelete test.db
        !            31: sqlite3 db test.db
        !            32: 
        !            33: ifcapable autovacuum {
        !            34:   do_test shared-[expr $av+1].1.0 {
        !            35:     execsql "pragma auto_vacuum=$::av"
        !            36:     execsql {pragma auto_vacuum}
        !            37:   } "$av"
        !            38: } else {
        !            39:   if {$av} {
        !            40:     db close
        !            41:     break
        !            42:   }
        !            43: }
        !            44: 
        !            45: # if we're using proxy locks, we use 2 filedescriptors for a db
        !            46: # that is open but NOT yet locked, after a lock is taken we'll have 3, 
        !            47: # normally sqlite uses 1 (proxy locking adds the conch and the local lock)
        !            48: set using_proxy 0
        !            49: foreach {name value} [array get env SQLITE_FORCE_PROXY_LOCKING] {
        !            50:   set using_proxy $value
        !            51: }
        !            52: set extrafds_prelock 0
        !            53: set extrafds_postlock 0
        !            54: if {$using_proxy>0} {
        !            55:   set extrafds_prelock 1
        !            56:   set extrafds_postlock 2
        !            57: } 
        !            58: 
        !            59: # $av is currently 0 if this loop iteration is to test with auto-vacuum turned
        !            60: # off, and 1 if it is turned on. Increment it so that (1 -> no auto-vacuum) 
        !            61: # and (2 -> auto-vacuum). The sole reason for this is so that it looks nicer
        !            62: # when we use this variable as part of test-case names.
        !            63: #
        !            64: incr av
        !            65: 
        !            66: # Test organization:
        !            67: #
        !            68: # shared-1.*: Simple test to verify basic sanity of table level locking when
        !            69: #             two connections share a pager cache.
        !            70: # shared-2.*: Test that a read transaction can co-exist with a 
        !            71: #             write-transaction, including a simple test to ensure the 
        !            72: #             external locking protocol is still working.
        !            73: # shared-3.*: Simple test of read-uncommitted mode.
        !            74: # shared-4.*: Check that the schema is locked and unlocked correctly.
        !            75: # shared-5.*: Test that creating/dropping schema items works when databases
        !            76: #             are attached in different orders to different handles.
        !            77: # shared-6.*: Locking, UNION ALL queries and sub-queries.
        !            78: # shared-7.*: Autovacuum and shared-cache.
        !            79: # shared-8.*: Tests related to the text encoding of shared-cache databases.
        !            80: # shared-9.*: TEMP triggers and shared-cache databases.
        !            81: # shared-10.*: Tests of sqlite3_close().
        !            82: # shared-11.*: Test transaction locking.
        !            83: #
        !            84: 
        !            85: do_test shared-$av.1.1 {
        !            86:   # Open a second database on the file test.db. It should use the same pager
        !            87:   # cache and schema as the original connection. Verify that only 1 file is 
        !            88:   # opened.
        !            89:   sqlite3 db2 test.db
        !            90:   set ::sqlite_open_file_count
        !            91:   expr $sqlite_open_file_count-$extrafds_postlock
        !            92: } {1}
        !            93: do_test shared-$av.1.2 {
        !            94:   # Add a table and a single row of data via the first connection. 
        !            95:   # Ensure that the second connection can see them.
        !            96:   execsql {
        !            97:     CREATE TABLE abc(a, b, c);
        !            98:     INSERT INTO abc VALUES(1, 2, 3);
        !            99:   } db
        !           100:   execsql {
        !           101:     SELECT * FROM abc;
        !           102:   } db2
        !           103: } {1 2 3}
        !           104: do_test shared-$av.1.3 {
        !           105:   # Have the first connection begin a transaction and obtain a read-lock
        !           106:   # on table abc. This should not prevent the second connection from 
        !           107:   # querying abc.
        !           108:   execsql {
        !           109:     BEGIN;
        !           110:     SELECT * FROM abc;
        !           111:   }
        !           112:   execsql {
        !           113:     SELECT * FROM abc;
        !           114:   } db2
        !           115: } {1 2 3}
        !           116: do_test shared-$av.1.4 {
        !           117:   # Try to insert a row into abc via connection 2. This should fail because
        !           118:   # of the read-lock connection 1 is holding on table abc (obtained in the
        !           119:   # previous test case).
        !           120:   catchsql {
        !           121:     INSERT INTO abc VALUES(4, 5, 6);
        !           122:   } db2
        !           123: } {1 {database table is locked: abc}}
        !           124: do_test shared-$av.1.5 {
        !           125:   # Using connection 2 (the one without the open transaction), try to create
        !           126:   # a new table. This should fail because of the open read transaction 
        !           127:   # held by connection 1.
        !           128:   catchsql {
        !           129:     CREATE TABLE def(d, e, f);
        !           130:   } db2
        !           131: } {1 {database table is locked: sqlite_master}}
        !           132: do_test shared-$av.1.6 {
        !           133:   # Upgrade connection 1's transaction to a write transaction. Create
        !           134:   # a new table - def - and insert a row into it. Because the connection 1
        !           135:   # transaction modifies the schema, it should not be possible for 
        !           136:   # connection 2 to access the database at all until the connection 1 
        !           137:   # has finished the transaction.
        !           138:   execsql {
        !           139:     CREATE TABLE def(d, e, f);
        !           140:     INSERT INTO def VALUES('IV', 'V', 'VI');
        !           141:   }
        !           142: } {}
        !           143: do_test shared-$av.1.7 {
        !           144:   # Read from the sqlite_master table with connection 1 (inside the 
        !           145:   # transaction). Then test that we can not do this with connection 2. This
        !           146:   # is because of the schema-modified lock established by connection 1 
        !           147:   # in the previous test case.
        !           148:   execsql {
        !           149:     SELECT * FROM sqlite_master;
        !           150:   }
        !           151:   catchsql {
        !           152:     SELECT * FROM sqlite_master;
        !           153:   } db2
        !           154: } {1 {database schema is locked: main}}
        !           155: do_test shared-$av.1.8 {
        !           156:   # Commit the connection 1 transaction.
        !           157:   execsql {
        !           158:     COMMIT;
        !           159:   }
        !           160: } {}
        !           161: 
        !           162: do_test shared-$av.2.1 {
        !           163:   # Open connection db3 to the database. Use a different path to the same
        !           164:   # file so that db3 does *not* share the same pager cache as db and db2
        !           165:   # (there should be two open file handles).
        !           166:   if {$::tcl_platform(platform)=="unix"} {
        !           167:     sqlite3 db3 ./test.db
        !           168:   } else {
        !           169:     sqlite3 db3 TEST.DB
        !           170:   }
        !           171:   set ::sqlite_open_file_count
        !           172:   expr $sqlite_open_file_count-($extrafds_prelock+$extrafds_postlock)
        !           173: } {2}
        !           174: do_test shared-$av.2.2 {
        !           175:   # Start read transactions on db and db2 (the shared pager cache). Ensure
        !           176:   # db3 cannot write to the database.
        !           177:   execsql {
        !           178:     BEGIN;
        !           179:     SELECT * FROM abc;
        !           180:   }
        !           181:   execsql {
        !           182:     BEGIN;
        !           183:     SELECT * FROM abc;
        !           184:   } db2
        !           185:   catchsql {
        !           186:     INSERT INTO abc VALUES(1, 2, 3);
        !           187:   } db2
        !           188: } {1 {database table is locked: abc}}
        !           189: do_test shared-$av.2.3 {
        !           190:   # Turn db's transaction into a write-transaction. db3 should still be
        !           191:   # able to read from table def (but will not see the new row). Connection
        !           192:   # db2 should not be able to read def (because of the write-lock).
        !           193: 
        !           194: # Todo: The failed "INSERT INTO abc ..." statement in the above test
        !           195: # has started a write-transaction on db2 (should this be so?). This 
        !           196: # would prevent connection db from starting a write-transaction. So roll the
        !           197: # db2 transaction back and replace it with a new read transaction.
        !           198:   execsql {
        !           199:     ROLLBACK;
        !           200:     BEGIN;
        !           201:     SELECT * FROM abc;
        !           202:   } db2
        !           203: 
        !           204:   execsql {
        !           205:     INSERT INTO def VALUES('VII', 'VIII', 'IX');
        !           206:   }
        !           207:   concat [
        !           208:     catchsql { SELECT * FROM def; } db3
        !           209:   ] [
        !           210:     catchsql { SELECT * FROM def; } db2
        !           211:   ]
        !           212: } {0 {IV V VI} 1 {database table is locked: def}}
        !           213: do_test shared-$av.2.4 {
        !           214:   # Commit the open transaction on db. db2 still holds a read-transaction.
        !           215:   # This should prevent db3 from writing to the database, but not from 
        !           216:   # reading.
        !           217:   execsql {
        !           218:     COMMIT;
        !           219:   }
        !           220:   concat [
        !           221:     catchsql { SELECT * FROM def; } db3
        !           222:   ] [
        !           223:     catchsql { INSERT INTO def VALUES('X', 'XI', 'XII'); } db3
        !           224:   ]
        !           225: } {0 {IV V VI VII VIII IX} 1 {database is locked}}
        !           226: 
        !           227: catchsql COMMIT db2
        !           228: 
        !           229: do_test shared-$av.3.1.1 {
        !           230:   # This test case starts a linear scan of table 'seq' using a 
        !           231:   # read-uncommitted connection. In the middle of the scan, rows are added
        !           232:   # to the end of the seq table (ahead of the current cursor position).
        !           233:   # The uncommitted rows should be included in the results of the scan.
        !           234:   execsql "
        !           235:     CREATE TABLE seq(i PRIMARY KEY, x);
        !           236:     INSERT INTO seq VALUES(1, '[string repeat X 500]');
        !           237:     INSERT INTO seq VALUES(2, '[string repeat X 500]');
        !           238:   "
        !           239:   execsql {SELECT * FROM sqlite_master} db2
        !           240:   execsql {PRAGMA read_uncommitted = 1} db2
        !           241: 
        !           242:   set ret [list]
        !           243:   db2 eval {SELECT i FROM seq ORDER BY i} {
        !           244:     if {$i < 4} {
        !           245:       set max [execsql {SELECT max(i) FROM seq}]
        !           246:       db eval {
        !           247:         INSERT INTO seq SELECT i + :max, x FROM seq;
        !           248:       }
        !           249:     }
        !           250:     lappend ret $i
        !           251:   }
        !           252:   set ret
        !           253: } {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16}
        !           254: do_test shared-$av.3.1.2 {
        !           255:   # Another linear scan through table seq using a read-uncommitted connection.
        !           256:   # This time, delete each row as it is read. Should not affect the results of
        !           257:   # the scan, but the table should be empty after the scan is concluded 
        !           258:   # (test 3.1.3 verifies this).
        !           259:   set ret [list]
        !           260:   db2 eval {SELECT i FROM seq} {
        !           261:     db eval {DELETE FROM seq WHERE i = :i}
        !           262:     lappend ret $i
        !           263:   }
        !           264:   set ret
        !           265: } {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16}
        !           266: do_test shared-$av.3.1.3 {
        !           267:   execsql {
        !           268:     SELECT * FROM seq;
        !           269:   }
        !           270: } {}
        !           271: 
        !           272: catch {db close}
        !           273: catch {db2 close}
        !           274: catch {db3 close}
        !           275: 
        !           276: #--------------------------------------------------------------------------
        !           277: # Tests shared-4.* test that the schema locking rules are applied 
        !           278: # correctly. i.e.:
        !           279: #
        !           280: # 1. All transactions require a read-lock on the schemas of databases they
        !           281: #    access.
        !           282: # 2. Transactions that modify a database schema require a write-lock on that
        !           283: #    schema.
        !           284: # 3. It is not possible to compile a statement while another handle has a 
        !           285: #    write-lock on the schema.
        !           286: #
        !           287: 
        !           288: # Open two database handles db and db2. Each has a single attach database
        !           289: # (as well as main):
        !           290: #
        !           291: #     db.main   ->   ./test.db
        !           292: #     db.test2  ->   ./test2.db
        !           293: #     db2.main  ->   ./test2.db
        !           294: #     db2.test  ->   ./test.db
        !           295: #
        !           296: forcedelete test.db
        !           297: forcedelete test2.db
        !           298: forcedelete test2.db-journal
        !           299: sqlite3 db  test.db
        !           300: sqlite3 db2 test2.db
        !           301: do_test shared-$av.4.1.1 {
        !           302:   set sqlite_open_file_count
        !           303:   expr $sqlite_open_file_count-($extrafds_prelock*2)
        !           304: } {2}
        !           305: do_test shared-$av.4.1.2 {
        !           306:   execsql {ATTACH 'test2.db' AS test2}
        !           307:   set sqlite_open_file_count
        !           308:   expr $sqlite_open_file_count-($extrafds_postlock*2)
        !           309: } {2}
        !           310: do_test shared-$av.4.1.3 {
        !           311:   execsql {ATTACH 'test.db' AS test} db2
        !           312:   set sqlite_open_file_count
        !           313:   expr $sqlite_open_file_count-($extrafds_postlock*2)
        !           314: } {2}
        !           315: 
        !           316: # Sanity check: Create a table in ./test.db via handle db, and test that handle
        !           317: # db2 can "see" the new table immediately. A handle using a seperate pager
        !           318: # cache would have to reload the database schema before this were possible.
        !           319: #
        !           320: do_test shared-$av.4.2.1 {
        !           321:   execsql {
        !           322:     CREATE TABLE abc(a, b, c);
        !           323:     CREATE TABLE def(d, e, f);
        !           324:     INSERT INTO abc VALUES('i', 'ii', 'iii');
        !           325:     INSERT INTO def VALUES('I', 'II', 'III');
        !           326:   }
        !           327: } {}
        !           328: do_test shared-$av.4.2.2 {
        !           329:   execsql {
        !           330:     SELECT * FROM test.abc;
        !           331:   } db2
        !           332: } {i ii iii}
        !           333: 
        !           334: # Open a read-transaction and read from table abc via handle 2. Check that
        !           335: # handle 1 can read table abc. Check that handle 1 cannot modify table abc
        !           336: # or the database schema. Then check that handle 1 can modify table def.
        !           337: #
        !           338: do_test shared-$av.4.3.1 {
        !           339:   execsql {
        !           340:     BEGIN;
        !           341:     SELECT * FROM test.abc;
        !           342:   } db2
        !           343: } {i ii iii}
        !           344: do_test shared-$av.4.3.2 {
        !           345:   catchsql {
        !           346:     INSERT INTO abc VALUES('iv', 'v', 'vi');
        !           347:   }
        !           348: } {1 {database table is locked: abc}}
        !           349: do_test shared-$av.4.3.3 {
        !           350:   catchsql {
        !           351:     CREATE TABLE ghi(g, h, i);
        !           352:   }
        !           353: } {1 {database table is locked: sqlite_master}}
        !           354: do_test shared-$av.4.3.3 {
        !           355:   catchsql {
        !           356:     INSERT INTO def VALUES('IV', 'V', 'VI');
        !           357:   }
        !           358: } {0 {}}
        !           359: do_test shared-$av.4.3.4 {
        !           360:   # Cleanup: commit the transaction opened by db2.
        !           361:   execsql {
        !           362:     COMMIT
        !           363:   } db2
        !           364: } {}
        !           365: 
        !           366: # Open a write-transaction using handle 1 and modify the database schema.
        !           367: # Then try to execute a compiled statement to read from the same 
        !           368: # database via handle 2 (fails to get the lock on sqlite_master). Also
        !           369: # try to compile a read of the same database using handle 2 (also fails).
        !           370: # Finally, compile a read of the other database using handle 2. This
        !           371: # should also fail.
        !           372: #
        !           373: ifcapable compound {
        !           374:   do_test shared-$av.4.4.1.2 {
        !           375:     # Sanity check 1: Check that the schema is what we think it is when viewed
        !           376:     # via handle 1.
        !           377:     execsql {
        !           378:       CREATE TABLE test2.ghi(g, h, i);
        !           379:       SELECT 'test.db:'||name FROM sqlite_master 
        !           380:       UNION ALL
        !           381:       SELECT 'test2.db:'||name FROM test2.sqlite_master;
        !           382:     }
        !           383:   } {test.db:abc test.db:def test2.db:ghi}
        !           384:   do_test shared-$av.4.4.1.2 {
        !           385:     # Sanity check 2: Check that the schema is what we think it is when viewed
        !           386:     # via handle 2.
        !           387:     execsql {
        !           388:       SELECT 'test2.db:'||name FROM sqlite_master 
        !           389:       UNION ALL
        !           390:       SELECT 'test.db:'||name FROM test.sqlite_master;
        !           391:     } db2
        !           392:   } {test2.db:ghi test.db:abc test.db:def}
        !           393: }
        !           394: 
        !           395: do_test shared-$av.4.4.2 {
        !           396:   set ::DB2 [sqlite3_connection_pointer db2]
        !           397:   set sql {SELECT * FROM abc}
        !           398:   set ::STMT1 [sqlite3_prepare $::DB2 $sql -1 DUMMY]
        !           399:   execsql {
        !           400:     BEGIN;
        !           401:     CREATE TABLE jkl(j, k, l);
        !           402:   }
        !           403:   sqlite3_step $::STMT1
        !           404: } {SQLITE_ERROR}
        !           405: do_test shared-$av.4.4.3 {
        !           406:   sqlite3_finalize $::STMT1
        !           407: } {SQLITE_LOCKED}
        !           408: do_test shared-$av.4.4.4 {
        !           409:   set rc [catch {
        !           410:     set ::STMT1 [sqlite3_prepare $::DB2 $sql -1 DUMMY]
        !           411:   } msg]
        !           412:   list $rc $msg
        !           413: } {1 {(6) database schema is locked: test}}
        !           414: do_test shared-$av.4.4.5 {
        !           415:   set rc [catch {
        !           416:     set ::STMT1 [sqlite3_prepare $::DB2 "SELECT * FROM ghi" -1 DUMMY]
        !           417:   } msg]
        !           418:   list $rc $msg
        !           419: } {1 {(6) database schema is locked: test}}
        !           420: 
        !           421: 
        !           422: catch {db2 close}
        !           423: catch {db close}
        !           424: 
        !           425: #--------------------------------------------------------------------------
        !           426: # Tests shared-5.* 
        !           427: #
        !           428: foreach db [list test.db test1.db test2.db test3.db] {
        !           429:   forcedelete $db ${db}-journal
        !           430: }
        !           431: do_test shared-$av.5.1.1 {
        !           432:   sqlite3 db1 test.db
        !           433:   sqlite3 db2 test.db
        !           434:   execsql {
        !           435:     ATTACH 'test1.db' AS test1;
        !           436:     ATTACH 'test2.db' AS test2;
        !           437:     ATTACH 'test3.db' AS test3;
        !           438:   } db1
        !           439:   execsql {
        !           440:     ATTACH 'test3.db' AS test3;
        !           441:     ATTACH 'test2.db' AS test2;
        !           442:     ATTACH 'test1.db' AS test1;
        !           443:   } db2
        !           444: } {}
        !           445: do_test shared-$av.5.1.2 {
        !           446:   execsql {
        !           447:     CREATE TABLE test1.t1(a, b);
        !           448:     CREATE INDEX test1.i1 ON t1(a, b);
        !           449:   } db1
        !           450: } {}
        !           451: ifcapable view {
        !           452:   do_test shared-$av.5.1.3 {
        !           453:     execsql {
        !           454:       CREATE VIEW test1.v1 AS SELECT * FROM t1;
        !           455:     } db1
        !           456:   } {}
        !           457: }
        !           458: ifcapable trigger {
        !           459:   do_test shared-$av.5.1.4 {
        !           460:     execsql {
        !           461:       CREATE TRIGGER test1.trig1 AFTER INSERT ON t1 BEGIN
        !           462:         INSERT INTO t1 VALUES(new.a, new.b);
        !           463:       END;
        !           464:     } db1
        !           465:   } {}
        !           466: }
        !           467: do_test shared-$av.5.1.5 {
        !           468:   execsql {
        !           469:     DROP INDEX i1;
        !           470:   } db2
        !           471: } {}
        !           472: ifcapable view {
        !           473:   do_test shared-$av.5.1.6 {
        !           474:     execsql {
        !           475:       DROP VIEW v1;
        !           476:     } db2
        !           477:   } {}
        !           478: }
        !           479: ifcapable trigger {
        !           480:   do_test shared-$av.5.1.7 {
        !           481:     execsql {
        !           482:       DROP TRIGGER trig1;
        !           483:     } db2
        !           484:   } {}
        !           485: }
        !           486: do_test shared-$av.5.1.8 {
        !           487:   execsql {
        !           488:     DROP TABLE t1;
        !           489:   } db2
        !           490: } {}
        !           491: ifcapable compound {
        !           492:   do_test shared-$av.5.1.9 {
        !           493:     execsql {
        !           494:       SELECT * FROM sqlite_master UNION ALL SELECT * FROM test1.sqlite_master
        !           495:     } db1
        !           496:   } {}
        !           497: }
        !           498: 
        !           499: #--------------------------------------------------------------------------
        !           500: # Tests shared-6.* test that a query obtains all the read-locks it needs
        !           501: # before starting execution of the query. This means that there is no chance
        !           502: # some rows of data will be returned before a lock fails and SQLITE_LOCK
        !           503: # is returned.
        !           504: #
        !           505: do_test shared-$av.6.1.1 {
        !           506:   execsql {
        !           507:     CREATE TABLE t1(a, b);
        !           508:     CREATE TABLE t2(a, b);
        !           509:     INSERT INTO t1 VALUES(1, 2);
        !           510:     INSERT INTO t2 VALUES(3, 4);
        !           511:   } db1
        !           512: } {}
        !           513: ifcapable compound {
        !           514:   do_test shared-$av.6.1.2 {
        !           515:     execsql {
        !           516:       SELECT * FROM t1 UNION ALL SELECT * FROM t2;
        !           517:     } db2
        !           518:   } {1 2 3 4}
        !           519: }
        !           520: do_test shared-$av.6.1.3 {
        !           521:   # Establish a write lock on table t2 via connection db2. Then make a 
        !           522:   # UNION all query using connection db1 that first accesses t1, followed 
        !           523:   # by t2. If the locks are grabbed at the start of the statement (as 
        !           524:   # they should be), no rows are returned. If (as was previously the case)
        !           525:   # they are grabbed as the tables are accessed, the t1 rows will be 
        !           526:   # returned before the query fails.
        !           527:   #
        !           528:   execsql {
        !           529:     BEGIN;
        !           530:     INSERT INTO t2 VALUES(5, 6);
        !           531:   } db2
        !           532:   set ret [list]
        !           533:   catch {
        !           534:     db1 eval {SELECT * FROM t1 UNION ALL SELECT * FROM t2} {
        !           535:       lappend ret $a $b
        !           536:     }
        !           537:   }
        !           538:   set ret
        !           539: } {}
        !           540: do_test shared-$av.6.1.4 {
        !           541:   execsql {
        !           542:     COMMIT;
        !           543:     BEGIN;
        !           544:     INSERT INTO t1 VALUES(7, 8);
        !           545:   } db2
        !           546:   set ret [list]
        !           547:   catch {
        !           548:     db1 eval {
        !           549:       SELECT (CASE WHEN a>4 THEN (SELECT a FROM t1) ELSE 0 END) AS d FROM t2;
        !           550:     } {
        !           551:       lappend ret $d
        !           552:     }
        !           553:   }
        !           554:   set ret
        !           555: } {}
        !           556: 
        !           557: catch {db1 close}
        !           558: catch {db2 close}
        !           559: foreach f [list test.db test2.db] {
        !           560:   forcedelete $f ${f}-journal
        !           561: }
        !           562: 
        !           563: #--------------------------------------------------------------------------
        !           564: # Tests shared-7.* test auto-vacuum does not invalidate cursors from
        !           565: # other shared-cache users when it reorganizes the database on 
        !           566: # COMMIT.
        !           567: #
        !           568: do_test shared-$av.7.1 {
        !           569:   # This test case sets up a test database in auto-vacuum mode consisting 
        !           570:   # of two tables, t1 and t2. Both have a single index. Table t1 is 
        !           571:   # populated first (so consists of pages toward the start of the db file), 
        !           572:   # t2 second (pages toward the end of the file). 
        !           573:   sqlite3 db test.db
        !           574:   sqlite3 db2 test.db
        !           575:   execsql {
        !           576:     BEGIN;
        !           577:     CREATE TABLE t1(a PRIMARY KEY, b);
        !           578:     CREATE TABLE t2(a PRIMARY KEY, b);
        !           579:   }
        !           580:   set ::contents {}
        !           581:   for {set i 0} {$i < 100} {incr i} {
        !           582:     set a [string repeat "$i " 20]
        !           583:     set b [string repeat "$i " 20]
        !           584:     db eval {
        !           585:       INSERT INTO t1 VALUES(:a, :b);
        !           586:     }
        !           587:     lappend ::contents [list [expr $i+1] $a $b]
        !           588:   }
        !           589:   execsql {
        !           590:     INSERT INTO t2 SELECT * FROM t1;
        !           591:     COMMIT;
        !           592:   }
        !           593: } {}
        !           594: do_test shared-$av.7.2 {
        !           595:   # This test case deletes the contents of table t1 (the one at the start of
        !           596:   # the file) while many cursors are open on table t2 and its index. All of
        !           597:   # the non-root pages will be moved from the end to the start of the file
        !           598:   # when the DELETE is committed - this test verifies that moving the pages
        !           599:   # does not disturb the open cursors.
        !           600:   #
        !           601: 
        !           602:   proc lockrow {db tbl oids body} {
        !           603:     set ret [list]
        !           604:     db eval "SELECT oid AS i, a, b FROM $tbl ORDER BY a" {
        !           605:       if {$i==[lindex $oids 0]} {
        !           606:         set noids [lrange $oids 1 end]
        !           607:         if {[llength $noids]==0} {
        !           608:           set subret [eval $body]
        !           609:         } else {
        !           610:           set subret [lockrow $db $tbl $noids $body]
        !           611:         }
        !           612:       }
        !           613:       lappend ret [list $i $a $b]
        !           614:     }
        !           615:     return [linsert $subret 0 $ret]
        !           616:   }
        !           617:   proc locktblrows {db tbl body} {
        !           618:     set oids [db eval "SELECT oid FROM $tbl"]
        !           619:     lockrow $db $tbl $oids $body
        !           620:   }
        !           621: 
        !           622:   set scans [locktblrows db t2 {
        !           623:     execsql {
        !           624:       DELETE FROM t1;
        !           625:     } db2
        !           626:   }]
        !           627:   set error 0
        !           628: 
        !           629:   # Test that each SELECT query returned the expected contents of t2.
        !           630:   foreach s $scans {
        !           631:     if {[lsort -integer -index 0 $s]!=$::contents} {
        !           632:       set error 1
        !           633:     }
        !           634:   }
        !           635:   set error
        !           636: } {0}
        !           637: 
        !           638: catch {db close}
        !           639: catch {db2 close}
        !           640: unset -nocomplain contents
        !           641: 
        !           642: #--------------------------------------------------------------------------
        !           643: # The following tests try to trick the shared-cache code into assuming
        !           644: # the wrong encoding for a database.
        !           645: #
        !           646: forcedelete test.db test.db-journal
        !           647: ifcapable utf16 {
        !           648:   do_test shared-$av.8.1.1 {
        !           649:     sqlite3 db test.db
        !           650:     execsql {
        !           651:       PRAGMA encoding = 'UTF-16';
        !           652:       SELECT * FROM sqlite_master;
        !           653:     }
        !           654:   } {}
        !           655:   do_test shared-$av.8.1.2 {
        !           656:     string range [execsql {PRAGMA encoding;}] 0 end-2
        !           657:   } {UTF-16}
        !           658: 
        !           659:   do_test shared-$av.8.1.3 {
        !           660:     sqlite3 db2 test.db
        !           661:     execsql {
        !           662:       PRAGMA encoding = 'UTF-8';
        !           663:       CREATE TABLE abc(a, b, c);
        !           664:     } db2
        !           665:   } {}
        !           666:   do_test shared-$av.8.1.4 {
        !           667:     execsql {
        !           668:       SELECT * FROM sqlite_master;
        !           669:     }
        !           670:   } "table abc abc [expr $AUTOVACUUM?3:2] {CREATE TABLE abc(a, b, c)}"
        !           671:   do_test shared-$av.8.1.5 {
        !           672:     db2 close
        !           673:     execsql {
        !           674:       PRAGMA encoding;
        !           675:     }
        !           676:   } {UTF-8}
        !           677: 
        !           678:   forcedelete test2.db test2.db-journal
        !           679:   do_test shared-$av.8.2.1 {
        !           680:     execsql {
        !           681:       ATTACH 'test2.db' AS aux;
        !           682:       SELECT * FROM aux.sqlite_master;
        !           683:     }
        !           684:   } {}
        !           685:   do_test shared-$av.8.2.2 {
        !           686:     sqlite3 db2 test2.db
        !           687:     execsql {
        !           688:       PRAGMA encoding = 'UTF-16';
        !           689:       CREATE TABLE def(d, e, f);
        !           690:     } db2
        !           691:     string range [execsql {PRAGMA encoding;} db2] 0 end-2
        !           692:   } {UTF-16}
        !           693: 
        !           694:   catch {db close}
        !           695:   catch {db2 close}
        !           696:   forcedelete test.db test2.db
        !           697: 
        !           698:   do_test shared-$av.8.3.2 {
        !           699:     sqlite3 db test.db
        !           700:     execsql { CREATE TABLE def(d, e, f) }
        !           701:     execsql { PRAGMA encoding }
        !           702:   } {UTF-8}
        !           703:   do_test shared-$av.8.3.3 {
        !           704:     set zDb16 "[encoding convertto unicode test.db]\x00\x00"
        !           705:     set db16 [sqlite3_open16 $zDb16 {}]
        !           706: 
        !           707:     set stmt [sqlite3_prepare $db16 "SELECT sql FROM sqlite_master" -1 DUMMY]
        !           708:     sqlite3_step $stmt
        !           709:     set sql [sqlite3_column_text $stmt 0]
        !           710:     sqlite3_finalize $stmt
        !           711:     set sql
        !           712:   } {CREATE TABLE def(d, e, f)}
        !           713:   do_test shared-$av.8.3.4 {
        !           714:     set stmt [sqlite3_prepare $db16 "PRAGMA encoding" -1 DUMMY]
        !           715:     sqlite3_step $stmt
        !           716:     set enc [sqlite3_column_text $stmt 0]
        !           717:     sqlite3_finalize $stmt
        !           718:     set enc
        !           719:   } {UTF-8}
        !           720: 
        !           721:   sqlite3_close $db16
        !           722: 
        !           723: # Bug #2547 is causing this to fail.
        !           724: if 0 {
        !           725:   do_test shared-$av.8.2.3 {
        !           726:     catchsql {
        !           727:       SELECT * FROM aux.sqlite_master;
        !           728:     }
        !           729:   } {1 {attached databases must use the same text encoding as main database}}
        !           730: }
        !           731: }
        !           732: 
        !           733: catch {db close}
        !           734: catch {db2 close}
        !           735: forcedelete test.db test2.db
        !           736: 
        !           737: #---------------------------------------------------------------------------
        !           738: # The following tests - shared-9.* - test interactions between TEMP triggers
        !           739: # and shared-schemas.
        !           740: #
        !           741: ifcapable trigger&&tempdb {
        !           742: 
        !           743: do_test shared-$av.9.1 {
        !           744:   sqlite3 db test.db
        !           745:   sqlite3 db2 test.db
        !           746:   execsql {
        !           747:     CREATE TABLE abc(a, b, c);
        !           748:     CREATE TABLE abc_mirror(a, b, c);
        !           749:     CREATE TEMP TRIGGER BEFORE INSERT ON abc BEGIN 
        !           750:       INSERT INTO abc_mirror(a, b, c) VALUES(new.a, new.b, new.c);
        !           751:     END;
        !           752:     INSERT INTO abc VALUES(1, 2, 3);
        !           753:     SELECT * FROM abc_mirror;
        !           754:   }
        !           755: } {1 2 3}
        !           756: do_test shared-$av.9.2 {
        !           757:   execsql {
        !           758:     INSERT INTO abc VALUES(4, 5, 6);
        !           759:     SELECT * FROM abc_mirror;
        !           760:   } db2
        !           761: } {1 2 3}
        !           762: do_test shared-$av.9.3 {
        !           763:   db close
        !           764:   db2 close
        !           765: } {}
        !           766: 
        !           767: } ; # End shared-9.*
        !           768: 
        !           769: #---------------------------------------------------------------------------
        !           770: # The following tests - shared-10.* - test that the library behaves 
        !           771: # correctly when a connection to a shared-cache is closed. 
        !           772: #
        !           773: do_test shared-$av.10.1 {
        !           774:   # Create a small sample database with two connections to it (db and db2).
        !           775:   forcedelete test.db
        !           776:   sqlite3 db  test.db
        !           777:   sqlite3 db2 test.db
        !           778:   execsql {
        !           779:     CREATE TABLE ab(a PRIMARY KEY, b);
        !           780:     CREATE TABLE de(d PRIMARY KEY, e);
        !           781:     INSERT INTO ab VALUES('Chiang Mai', 100000);
        !           782:     INSERT INTO ab VALUES('Bangkok', 8000000);
        !           783:     INSERT INTO de VALUES('Ubon', 120000);
        !           784:     INSERT INTO de VALUES('Khon Kaen', 200000);
        !           785:   }
        !           786: } {}
        !           787: do_test shared-$av.10.2 {
        !           788:   # Open a read-transaction with the first connection, a write-transaction
        !           789:   # with the second.
        !           790:   execsql {
        !           791:     BEGIN;
        !           792:     SELECT * FROM ab;
        !           793:   }
        !           794:   execsql {
        !           795:     BEGIN;
        !           796:     INSERT INTO de VALUES('Pataya', 30000);
        !           797:   } db2
        !           798: } {}
        !           799: do_test shared-$av.10.3 {
        !           800:   # An external connection should be able to read the database, but not
        !           801:   # prepare a write operation.
        !           802:   if {$::tcl_platform(platform)=="unix"} {
        !           803:     sqlite3 db3 ./test.db
        !           804:   } else {
        !           805:     sqlite3 db3 TEST.DB
        !           806:   }
        !           807:   execsql {
        !           808:     SELECT * FROM ab;
        !           809:   } db3
        !           810:   catchsql {
        !           811:     BEGIN;
        !           812:     INSERT INTO de VALUES('Pataya', 30000);
        !           813:   } db3
        !           814: } {1 {database is locked}}
        !           815: do_test shared-$av.10.4 {
        !           816:   # Close the connection with the write-transaction open
        !           817:   db2 close
        !           818: } {}
        !           819: do_test shared-$av.10.5 {
        !           820:   # Test that the db2 transaction has been automatically rolled back.
        !           821:   # If it has not the ('Pataya', 30000) entry will still be in the table.
        !           822:   execsql {
        !           823:     SELECT * FROM de;
        !           824:   }
        !           825: } {Ubon 120000 {Khon Kaen} 200000}
        !           826: do_test shared-$av.10.5 {
        !           827:   # Closing db2 should have dropped the shared-cache back to a read-lock.
        !           828:   # So db3 should be able to prepare a write...
        !           829:   catchsql {INSERT INTO de VALUES('Pataya', 30000);} db3
        !           830: } {0 {}}
        !           831: do_test shared-$av.10.6 {
        !           832:   # ... but not commit it.
        !           833:   catchsql {COMMIT} db3
        !           834: } {1 {database is locked}}
        !           835: do_test shared-$av.10.7 {
        !           836:   # Commit the (read-only) db transaction. Check via db3 to make sure the 
        !           837:   # contents of table "de" are still as they should be.
        !           838:   execsql {
        !           839:     COMMIT;
        !           840:   }
        !           841:   execsql {
        !           842:     SELECT * FROM de;
        !           843:   } db3
        !           844: } {Ubon 120000 {Khon Kaen} 200000 Pataya 30000}
        !           845: do_test shared-$av.10.9 {
        !           846:   # Commit the external transaction.
        !           847:   catchsql {COMMIT} db3
        !           848: } {0 {}}
        !           849: integrity_check shared-$av.10.10
        !           850: do_test shared-$av.10.11 {
        !           851:   db close
        !           852:   db3 close
        !           853: } {}
        !           854: 
        !           855: do_test shared-$av.11.1 {
        !           856:   forcedelete test.db
        !           857:   sqlite3 db  test.db
        !           858:   sqlite3 db2 test.db
        !           859:   execsql {
        !           860:     CREATE TABLE abc(a, b, c);
        !           861:     CREATE TABLE abc2(a, b, c);
        !           862:     BEGIN;
        !           863:     INSERT INTO abc VALUES(1, 2, 3);
        !           864:   }
        !           865: } {}
        !           866: do_test shared-$av.11.2 {
        !           867:   catchsql {BEGIN;} db2
        !           868:   catchsql {SELECT * FROM abc;} db2
        !           869: } {1 {database table is locked: abc}}
        !           870: do_test shared-$av.11.3 {
        !           871:   catchsql {BEGIN} db2
        !           872: } {1 {cannot start a transaction within a transaction}}
        !           873: do_test shared-$av.11.4 {
        !           874:   catchsql {SELECT * FROM abc2;} db2
        !           875: } {0 {}}
        !           876: do_test shared-$av.11.5 {
        !           877:   catchsql {INSERT INTO abc2 VALUES(1, 2, 3);} db2
        !           878: } {1 {database table is locked}}
        !           879: do_test shared-$av.11.6 {
        !           880:   catchsql {SELECT * FROM abc2}
        !           881: } {0 {}}
        !           882: do_test shared-$av.11.6 {
        !           883:   execsql {
        !           884:     ROLLBACK;
        !           885:     PRAGMA read_uncommitted = 1;
        !           886:   } db2
        !           887: } {}
        !           888: do_test shared-$av.11.7 {
        !           889:   execsql {
        !           890:     INSERT INTO abc2 VALUES(4, 5, 6);
        !           891:     INSERT INTO abc2 VALUES(7, 8, 9);
        !           892:   }
        !           893: } {}
        !           894: do_test shared-$av.11.8 {
        !           895:   set res [list]
        !           896:   db2 eval {
        !           897:     SELECT abc.a as I, abc2.a as II FROM abc, abc2;
        !           898:   } {
        !           899:     execsql {
        !           900:       DELETE FROM abc WHERE 1;
        !           901:     }
        !           902:     lappend res $I $II
        !           903:   }
        !           904:   set res
        !           905: } {1 4 {} 7}
        !           906: if {[llength [info command sqlite3_shared_cache_report]]==1} {
        !           907:   do_test shared-$av.11.9 {
        !           908:     string tolower [sqlite3_shared_cache_report]
        !           909:   } [string tolower [list [file nativename [file normalize test.db]] 2]]
        !           910: }
        !           911: 
        !           912: do_test shared-$av.11.11 {
        !           913:   db close
        !           914:   db2 close
        !           915: } {}
        !           916: 
        !           917: # This tests that if it is impossible to free any pages, SQLite will
        !           918: # exceed the limit set by PRAGMA cache_size.
        !           919: forcedelete test.db test.db-journal
        !           920: sqlite3 db test.db 
        !           921: ifcapable pager_pragmas {
        !           922:   do_test shared-$av.12.1 {
        !           923:     execsql {
        !           924:       PRAGMA cache_size = 10;
        !           925:       PRAGMA cache_size;
        !           926:     }
        !           927:   } {10}
        !           928: }
        !           929: do_test shared-$av.12.2 {
        !           930:   set ::db_handles [list]
        !           931:   for {set i 1} {$i < 15} {incr i} {
        !           932:     lappend ::db_handles db$i
        !           933:     sqlite3 db$i test.db 
        !           934:     execsql "CREATE TABLE db${i}(a, b, c)" db$i 
        !           935:     execsql "INSERT INTO db${i} VALUES(1, 2, 3)"
        !           936:   }
        !           937: } {}
        !           938: proc nested_select {handles} {
        !           939:   [lindex $handles 0] eval "SELECT * FROM [lindex $handles 0]" {
        !           940:     lappend ::res $a $b $c
        !           941:     if {[llength $handles]>1} {
        !           942:       nested_select [lrange $handles 1 end]
        !           943:     }
        !           944:   }
        !           945: }
        !           946: do_test shared-$av.12.3 {
        !           947:   set ::res [list]
        !           948:   nested_select $::db_handles
        !           949:   set ::res
        !           950: } [string range [string repeat "1 2 3 " [llength $::db_handles]] 0 end-1]
        !           951: 
        !           952: do_test shared-$av.12.X {
        !           953:   db close
        !           954:   foreach h $::db_handles { 
        !           955:     $h close
        !           956:   }
        !           957: } {}
        !           958: 
        !           959: # Internally, locks are acquired on shared B-Tree structures in the order
        !           960: # that the structures appear in the virtual memory address space. This
        !           961: # test case attempts to cause the order of the structures in memory 
        !           962: # to be different from the order in which they are attached to a given
        !           963: # database handle. This covers an extra line or two.
        !           964: #
        !           965: do_test shared-$av.13.1 {
        !           966:   forcedelete test2.db test3.db test4.db test5.db
        !           967:   sqlite3 db :memory:
        !           968:   execsql {
        !           969:     ATTACH 'test2.db' AS aux2;
        !           970:     ATTACH 'test3.db' AS aux3;
        !           971:     ATTACH 'test4.db' AS aux4;
        !           972:     ATTACH 'test5.db' AS aux5;
        !           973:     DETACH aux2;
        !           974:     DETACH aux3;
        !           975:     DETACH aux4;
        !           976:     ATTACH 'test2.db' AS aux2;
        !           977:     ATTACH 'test3.db' AS aux3;
        !           978:     ATTACH 'test4.db' AS aux4;
        !           979:   }
        !           980: } {}
        !           981: do_test shared-$av.13.2 {
        !           982:   execsql {
        !           983:     CREATE TABLE t1(a, b, c);
        !           984:     CREATE TABLE aux2.t2(a, b, c);
        !           985:     CREATE TABLE aux3.t3(a, b, c);
        !           986:     CREATE TABLE aux4.t4(a, b, c);
        !           987:     CREATE TABLE aux5.t5(a, b, c);
        !           988:     SELECT count(*) FROM 
        !           989:       aux2.sqlite_master, 
        !           990:       aux3.sqlite_master, 
        !           991:       aux4.sqlite_master, 
        !           992:       aux5.sqlite_master
        !           993:   }
        !           994: } {1}
        !           995: do_test shared-$av.13.3 {
        !           996:   db close
        !           997: } {}
        !           998: 
        !           999: # Test that nothing horrible happens if a connection to a shared B-Tree 
        !          1000: # structure is closed while some other connection has an open cursor.
        !          1001: #
        !          1002: do_test shared-$av.14.1 {
        !          1003:   sqlite3 db test.db
        !          1004:   sqlite3 db2 test.db
        !          1005:   execsql {SELECT name FROM sqlite_master}
        !          1006: } {db1 db2 db3 db4 db5 db6 db7 db8 db9 db10 db11 db12 db13 db14}
        !          1007: do_test shared-$av.14.2 {
        !          1008:   set res [list]
        !          1009:   db eval {SELECT name FROM sqlite_master} {
        !          1010:     if {$name eq "db7"} {
        !          1011:       db2 close
        !          1012:     }
        !          1013:     lappend res $name
        !          1014:   }
        !          1015:   set res
        !          1016: } {db1 db2 db3 db4 db5 db6 db7 db8 db9 db10 db11 db12 db13 db14}
        !          1017: do_test shared-$av.14.3 {
        !          1018:   db close
        !          1019: } {}
        !          1020: 
        !          1021: # Populate a database schema using connection [db]. Then drop it using
        !          1022: # [db2]. This is to try to find any points where shared-schema elements
        !          1023: # are allocated using the lookaside buffer of [db].
        !          1024: # 
        !          1025: # Mutexes are enabled for this test as that activates a couple of useful
        !          1026: # assert() statements in the C code.
        !          1027: #
        !          1028: do_test shared-$av-15.1 {
        !          1029:   forcedelete test.db
        !          1030:   sqlite3 db test.db -fullmutex 1
        !          1031:   sqlite3 db2 test.db -fullmutex 1
        !          1032:   execsql {
        !          1033:     CREATE TABLE t1(a, b, c);
        !          1034:     CREATE INDEX i1 ON t1(a, b);
        !          1035:     CREATE VIEW v1 AS SELECT * FROM t1; 
        !          1036:     CREATE VIEW v2 AS SELECT * FROM t1, v1 
        !          1037:                       WHERE t1.c=v1.c GROUP BY t1.a ORDER BY v1.b; 
        !          1038:     CREATE TRIGGER tr1 AFTER INSERT ON t1 
        !          1039:       WHEN new.a!=1
        !          1040:     BEGIN
        !          1041:       DELETE FROM t1 WHERE a=5;
        !          1042:       INSERT INTO t1 VALUES(1, 2, 3);
        !          1043:       UPDATE t1 SET c=c+1;
        !          1044:     END;
        !          1045: 
        !          1046:     INSERT INTO t1 VALUES(5, 6, 7);
        !          1047:     INSERT INTO t1 VALUES(8, 9, 10);
        !          1048:     INSERT INTO t1 VALUES(11, 12, 13);
        !          1049:     ANALYZE;
        !          1050:     SELECT * FROM t1;
        !          1051:   }
        !          1052: } {1 2 6 8 9 12 1 2 5 11 12 14 1 2 4}
        !          1053: do_test shared-$av-15.2 {
        !          1054:   execsql { DROP TABLE t1 } db2
        !          1055: } {}
        !          1056: db close
        !          1057: db2 close
        !          1058: 
        !          1059: }
        !          1060: 
        !          1061: sqlite3_enable_shared_cache $::enable_shared_cache
        !          1062: finish_test

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