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>