787 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			787 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| # 2007 April 26
 | |
| #
 | |
| # The author disclaims copyright to this source code.  In place of
 | |
| # a legal notice, here is a blessing:
 | |
| #
 | |
| #    May you do good and not evil.
 | |
| #    May you find forgiveness for yourself and forgive others.
 | |
| #    May you share freely, never taking more than you give.
 | |
| #
 | |
| #***********************************************************************
 | |
| # This file implements regression tests for SQLite library.  The
 | |
| # focus of this file is testing the incremental vacuum feature.
 | |
| #
 | |
| # Note: There are also some tests for incremental vacuum and IO 
 | |
| # errors in incrvacuum_ioerr.test.
 | |
| #
 | |
| # $Id: incrvacuum.test,v 1.23 2009/02/18 20:31:18 drh Exp $
 | |
| 
 | |
| set testdir [file dirname $argv0]
 | |
| source $testdir/tester.tcl
 | |
| 
 | |
| # If this build of the library does not support auto-vacuum, omit this
 | |
| # whole file.
 | |
| ifcapable {!autovacuum || !pragma} {
 | |
|   finish_test
 | |
|   return
 | |
| }
 | |
| 
 | |
| #---------------------------------------------------------------------
 | |
| # Test the pragma on an empty database.
 | |
| #
 | |
| do_test incrvacuum-1.1 {
 | |
|   execsql {
 | |
|     pragma auto_vacuum;
 | |
|   }
 | |
| } $sqlite_options(default_autovacuum)
 | |
| do_test incrvacuum-1.2.0 {
 | |
|   # File size is sometimes 1 instead of 0 due to the hack we put in
 | |
|   # to work around ticket #3260.  Search for comments on #3260 in
 | |
|   # os_unix.c.
 | |
|   expr {[file size test.db] > 1}
 | |
| } {0}
 | |
| do_test incrvacuum-1.2 {
 | |
|   # This command will create the database.
 | |
|   execsql {
 | |
|     pragma auto_vacuum = 'full';
 | |
|     pragma auto_vacuum;
 | |
|   }
 | |
| } {1}
 | |
| do_test incrvacuum-1.2.1 {
 | |
|   expr {[file size test.db] > 0}
 | |
| } {1}
 | |
| do_test incrvacuum-1.3 {
 | |
|   execsql {
 | |
|     pragma auto_vacuum = 'incremental';
 | |
|     pragma auto_vacuum;
 | |
|   }
 | |
| } {2}
 | |
| do_test incrvacuum-1.4 {
 | |
|   # In this case the invalid value is ignored and the auto_vacuum
 | |
|   # setting remains unchanged.
 | |
|   execsql {
 | |
|     pragma auto_vacuum = 'invalid';
 | |
|     pragma auto_vacuum;
 | |
|   }
 | |
| } {2}
 | |
| do_test incrvacuum-1.5 {
 | |
|   execsql {
 | |
|     pragma auto_vacuum = 1;
 | |
|     pragma auto_vacuum;
 | |
|   }
 | |
| } {1}
 | |
| do_test incrvacuum-1.6 {
 | |
|   execsql {
 | |
|     pragma auto_vacuum = '2';
 | |
|     pragma auto_vacuum;
 | |
|   }
 | |
| } {2}
 | |
| do_test incrvacuum-1.7 {
 | |
|   # Invalid value. auto_vacuum setting remains unchanged.
 | |
|   execsql {
 | |
|     pragma auto_vacuum = 5;
 | |
|     pragma auto_vacuum;
 | |
|   }
 | |
| } {2}
 | |
| 
 | |
| #---------------------------------------------------------------------
 | |
| # Test the pragma on a non-empty database. It is possible to toggle
 | |
| # the connection between "full" and "incremental" mode, but not to
 | |
| # change from either of these to "none", or from "none" to "full" or
 | |
| # "incremental".
 | |
| #
 | |
| do_test incrvacuum-2.1 {
 | |
|   execsql {
 | |
|     pragma auto_vacuum = 1;
 | |
|     CREATE TABLE abc(a, b, c);
 | |
|   }
 | |
| } {}
 | |
| do_test incrvacuum-2.2 {
 | |
|   execsql {
 | |
|     pragma auto_vacuum = 'none';
 | |
|     pragma auto_vacuum;
 | |
|   }
 | |
| } {1}
 | |
| do_test incrvacuum-2.2.1 {
 | |
|   db close
 | |
|   sqlite3 db test.db
 | |
|   execsql {
 | |
|     pragma auto_vacuum;
 | |
|   }
 | |
| } {1}
 | |
| do_test incrvacuum-2.3 {
 | |
|   execsql {
 | |
|     pragma auto_vacuum = 'incremental';
 | |
|     pragma auto_vacuum;
 | |
|   }
 | |
| } {2}
 | |
| do_test incrvacuum-2.4 {
 | |
|   execsql {
 | |
|     pragma auto_vacuum = 'full';
 | |
|     pragma auto_vacuum;
 | |
|   }
 | |
| } {1}
 | |
| 
 | |
| #---------------------------------------------------------------------
 | |
| # Test that when the auto_vacuum mode is "incremental", the database
 | |
| # does not shrink when pages are removed from it. But it does if
 | |
| # the mode is set to "full".
 | |
| #
 | |
| do_test incrvacuum-3.1 {
 | |
|   execsql {
 | |
|     pragma auto_vacuum;
 | |
|   }
 | |
| } {1}
 | |
| do_test incrvacuum-3.2 {
 | |
|   set ::str [string repeat 1234567890 110]
 | |
|   execsql {
 | |
|     PRAGMA auto_vacuum = 2;
 | |
|     BEGIN;
 | |
|     CREATE TABLE tbl2(str);
 | |
|     INSERT INTO tbl2 VALUES($::str);
 | |
|     COMMIT;
 | |
|   }
 | |
|   # 5 pages:
 | |
|   #
 | |
|   #   1 -> database header
 | |
|   #   2 -> first back-pointer page
 | |
|   #   3 -> table abc
 | |
|   #   4 -> table tbl2
 | |
|   #   5 -> table tbl2 overflow page.
 | |
|   #
 | |
|   expr {[file size test.db] / 1024}
 | |
| } {5}
 | |
| do_test incrvacuum-3.3 {
 | |
|   execsql {
 | |
|     DROP TABLE abc;
 | |
|     DELETE FROM tbl2;
 | |
|   }
 | |
|   expr {[file size test.db] / 1024}
 | |
| } {5}
 | |
| do_test incrvacuum-3.4 {
 | |
|   execsql {
 | |
|     PRAGMA auto_vacuum = 1;
 | |
|     INSERT INTO tbl2 VALUES('hello world');
 | |
|   }
 | |
|   expr {[file size test.db] / 1024}
 | |
| } {3}
 | |
| 
 | |
| #---------------------------------------------------------------------
 | |
| # Try to run a very simple incremental vacuum. Also verify that 
 | |
| # PRAGMA incremental_vacuum is a harmless no-op against a database that
 | |
| # does not support auto-vacuum.
 | |
| #
 | |
| do_test incrvacuum-4.1 {
 | |
|   set ::str [string repeat 1234567890 110]
 | |
|   execsql {
 | |
|     PRAGMA auto_vacuum = 2;
 | |
|     INSERT INTO tbl2 VALUES($::str);
 | |
|     CREATE TABLE tbl1(a, b, c);
 | |
|   }
 | |
|   expr {[file size test.db] / 1024}
 | |
| } {5}
 | |
| do_test incrvacuum-4.2 {
 | |
|   execsql {
 | |
|     DELETE FROM tbl2;
 | |
|     DROP TABLE tbl1;
 | |
|   }
 | |
|   expr {[file size test.db] / 1024}
 | |
| } {5}
 | |
| do_test incrvacuum-4.3 {
 | |
|   set ::nStep 0
 | |
|   db eval {pragma incremental_vacuum(10)} {
 | |
|     incr ::nStep
 | |
|   }
 | |
|   list [expr {[file size test.db] / 1024}] $::nStep
 | |
| } {3 2}
 | |
| 
 | |
| #---------------------------------------------------------------------
 | |
| # The following tests - incrvacuum-5.* - test incremental vacuum
 | |
| # from within a transaction.
 | |
| #
 | |
| do_test incrvacuum-5.1.1 {
 | |
|   expr {[file size test.db] / 1024}
 | |
| } {3}
 | |
| do_test incrvacuum-5.1.2 {
 | |
|   execsql {
 | |
|     BEGIN;
 | |
|     DROP TABLE tbl2;
 | |
|     PRAGMA incremental_vacuum;
 | |
|     COMMIT;
 | |
|   }
 | |
|   expr {[file size test.db] / 1024}
 | |
| } {1}
 | |
| 
 | |
| do_test incrvacuum-5.2.1 {
 | |
|   set ::str [string repeat abcdefghij 110]
 | |
|   execsql {
 | |
|     BEGIN;
 | |
|     CREATE TABLE tbl1(a);
 | |
|     INSERT INTO tbl1 VALUES($::str);
 | |
|     PRAGMA incremental_vacuum;                 -- this is a no-op.
 | |
|     COMMIT;
 | |
|   }
 | |
|   expr {[file size test.db] / 1024}
 | |
| } {4}
 | |
| do_test incrvacuum-5.2.2 {
 | |
|   set ::str [string repeat abcdefghij 110]
 | |
|   execsql {
 | |
|     BEGIN;
 | |
|     INSERT INTO tbl1 VALUES($::str);
 | |
|     INSERT INTO tbl1 SELECT * FROM tbl1;
 | |
|     DELETE FROM tbl1 WHERE oid%2;        -- Put 2 overflow pages on free-list.
 | |
|     COMMIT;
 | |
|   }
 | |
|   expr {[file size test.db] / 1024}
 | |
| } {7}
 | |
| do_test incrvacuum-5.2.3 {
 | |
|   execsql {
 | |
|     BEGIN;
 | |
|     PRAGMA incremental_vacuum;           -- Vacuum up the two pages.
 | |
|     CREATE TABLE tbl2(b);                -- Use one free page as a table root.
 | |
|     INSERT INTO tbl2 VALUES('a nice string');
 | |
|     COMMIT;
 | |
|   }
 | |
|   expr {[file size test.db] / 1024}
 | |
| } {6}
 | |
| do_test incrvacuum-5.2.4 {
 | |
|   execsql {
 | |
|     SELECT * FROM tbl2;
 | |
|   }
 | |
| } {{a nice string}}
 | |
| do_test incrvacuum-5.2.5 {
 | |
|   execsql {
 | |
|     DROP TABLE tbl1;
 | |
|     DROP TABLE tbl2;
 | |
|     PRAGMA incremental_vacuum;
 | |
|   }
 | |
|   expr {[file size test.db] / 1024}
 | |
| } {1}
 | |
| 
 | |
| 
 | |
| # Test cases incrvacuum-5.3.* use the following list as input data.
 | |
| # Two new databases are opened, one with incremental vacuum enabled,
 | |
| # the other with no auto-vacuum completely disabled. After executing
 | |
| # each element of the following list on both databases, test that
 | |
| # the integrity-check passes and the contents of each are identical.
 | |
| # 
 | |
| set TestScriptList [list {
 | |
|   BEGIN;
 | |
|   CREATE TABLE t1(a, b);
 | |
|   CREATE TABLE t2(a, b);
 | |
|   CREATE INDEX t1_i ON t1(a);
 | |
|   CREATE INDEX t2_i ON t2(a);
 | |
| } {
 | |
|   INSERT INTO t1 VALUES($::str1, $::str2);
 | |
|   INSERT INTO t1 VALUES($::str1||$::str2, $::str2||$::str1);
 | |
|   INSERT INTO t2 SELECT b, a FROM t1;
 | |
|   INSERT INTO t2 SELECT a, b FROM t1;
 | |
|   INSERT INTO t1 SELECT b, a FROM t2;
 | |
|   UPDATE t2 SET b = '';
 | |
|   PRAGMA incremental_vacuum;
 | |
| } {
 | |
|   UPDATE t2 SET b = (SELECT b FROM t1 WHERE t1.oid = t2.oid);
 | |
|   PRAGMA incremental_vacuum;
 | |
| } {
 | |
|   CREATE TABLE t3(a, b);
 | |
|   INSERT INTO t3 SELECT * FROM t2;
 | |
|   DROP TABLE t2;
 | |
|   PRAGMA incremental_vacuum;
 | |
| } {
 | |
|   CREATE INDEX t3_i ON t3(a);
 | |
|   COMMIT;
 | |
| } {
 | |
|   BEGIN;
 | |
|   DROP INDEX t3_i;
 | |
|   PRAGMA incremental_vacuum;
 | |
|   INSERT INTO t3 VALUES('hello', 'world');
 | |
|   ROLLBACK;
 | |
| } {
 | |
|   INSERT INTO t3 VALUES('hello', 'world');
 | |
| }
 | |
| ]
 | |
| 
 | |
| # If this build omits subqueries, step 2 in the above list will not
 | |
| # work. Replace it with "" in this case. 
 | |
| #
 | |
| ifcapable !subquery { lset TestScriptList 2 "" }
 | |
| 
 | |
| # Compare the contents of databases $A and $B.
 | |
| #
 | |
| proc compare_dbs {A B tname} {
 | |
|   set tbl_list [execsql {
 | |
|     SELECT tbl_name FROM sqlite_master WHERE type = 'table'
 | |
|   } $A]
 | |
| 
 | |
|   do_test ${tname}.1 [subst {
 | |
|     execsql {
 | |
|       SELECT tbl_name FROM sqlite_master WHERE type = 'table'
 | |
|     } $B
 | |
|   }] $tbl_list
 | |
| 
 | |
|   set tn 1
 | |
|   foreach tbl $tbl_list {
 | |
|     set control [execsql "SELECT * FROM $tbl" $A]
 | |
|     do_test ${tname}.[incr tn] [subst {
 | |
|       execsql "SELECT * FROM $tbl" $B
 | |
|     }] $control
 | |
|   }
 | |
| }
 | |
| 
 | |
| set ::str1 [string repeat abcdefghij 130]
 | |
| set ::str2 [string repeat 1234567890 105]
 | |
| 
 | |
| forcedelete test1.db test1.db-journal test2.db test2.db-journal
 | |
| sqlite3 db1 test1.db
 | |
| sqlite3 db2 test2.db
 | |
| execsql { PRAGMA auto_vacuum = 'none' } db1
 | |
| execsql { PRAGMA auto_vacuum = 'incremental' } db2
 | |
| 
 | |
| set tn 1
 | |
| foreach sql $::TestScriptList {
 | |
|   execsql $sql db1
 | |
|   execsql $sql db2
 | |
| 
 | |
|   compare_dbs db1 db2 incrvacuum-5.3.${tn}
 | |
|   do_test incrvacuum-5.3.${tn}.integrity1 {
 | |
|     execsql { PRAGMA integrity_check; } db1
 | |
|   } {ok}
 | |
|   do_test incrvacuum-5.3.${tn}.integrity2 {
 | |
|     execsql { PRAGMA integrity_check; } db2
 | |
|   } {ok}
 | |
|   incr tn
 | |
| }
 | |
| db1 close
 | |
| db2 close
 | |
| #
 | |
| # End of test cases 5.3.*
 | |
| 
 | |
| #---------------------------------------------------------------------
 | |
| # The following tests - incrvacuum-6.* - test running incremental 
 | |
| # vacuum while another statement (a read) is being executed.
 | |
| #
 | |
| for {set jj 0} {$jj < 10} {incr jj} {
 | |
|   # Build some test data. Two tables are created in an empty
 | |
|   # database. tbl1 data is a contiguous block starting at page 5 (pages
 | |
|   # 3 and 4 are the table roots). tbl2 is a contiguous block starting 
 | |
|   # right after tbl1.
 | |
|   #
 | |
|   # Then drop tbl1 so that when an incr vacuum is run the pages
 | |
|   # of tbl2 have to be moved to fill the gap.
 | |
|   #
 | |
|   do_test incrvacuum-6.${jj}.1 {
 | |
|     execsql {
 | |
|       DROP TABLE IF EXISTS tbl1;
 | |
|       DROP TABLE IF EXISTS tbl2;
 | |
|       PRAGMA incremental_vacuum;
 | |
|       CREATE TABLE tbl1(a, b);
 | |
|       CREATE TABLE tbl2(a, b);
 | |
|       BEGIN;
 | |
|     }
 | |
|     for {set ii 0} {$ii < 1000} {incr ii} {
 | |
|       db eval {INSERT INTO tbl1 VALUES($ii, $ii || $ii)}
 | |
|     }
 | |
|     execsql {
 | |
|       INSERT INTO tbl2 SELECT * FROM tbl1;
 | |
|       COMMIT;
 | |
|       DROP TABLE tbl1;
 | |
|     }
 | |
|     expr {[file size test.db] / 1024}
 | |
|   } {36}
 | |
| 
 | |
|   # Run a linear scan query on tbl2. After reading ($jj*100) rows, 
 | |
|   # run the incremental vacuum to shrink the database.
 | |
|   #
 | |
|   do_test incrvacuum-6.${jj}.2 {
 | |
|     set ::nRow 0
 | |
|     db eval {SELECT a FROM tbl2} {} {
 | |
|       if {$a == [expr $jj*100]} {
 | |
|         db eval {PRAGMA incremental_vacuum}
 | |
|       }
 | |
|       incr ::nRow
 | |
|     }
 | |
|     list [expr {[file size test.db] / 1024}] $nRow
 | |
|   } {19 1000}
 | |
| }
 | |
| 
 | |
| #---------------------------------------------------------------------
 | |
| # This test - incrvacuum-7.* - is to check that the database can be
 | |
| # written in the middle of an incremental vacuum.
 | |
| #
 | |
| set ::iWrite 1
 | |
| while 1 {
 | |
|   do_test incrvacuum-7.${::iWrite}.1 {
 | |
|     execsql {
 | |
|       DROP TABLE IF EXISTS tbl1;
 | |
|       DROP TABLE IF EXISTS tbl2;
 | |
|       PRAGMA incremental_vacuum;
 | |
|       CREATE TABLE tbl1(a, b);
 | |
|       CREATE TABLE tbl2(a, b);
 | |
|       BEGIN;
 | |
|     }
 | |
|     for {set ii 0} {$ii < 1000} {incr ii} {
 | |
|       db eval {INSERT INTO tbl1 VALUES($ii, $ii || $ii)}
 | |
|     }
 | |
|     execsql {
 | |
|       INSERT INTO tbl2 SELECT * FROM tbl1;
 | |
|       COMMIT;
 | |
|       DROP TABLE tbl1;
 | |
|     }
 | |
|     expr {[file size test.db] / 1024}
 | |
|   } {36}
 | |
| 
 | |
|   do_test incrvacuum-7.${::iWrite}.2 {
 | |
|     set ::nRow 0
 | |
|     db eval {PRAGMA incremental_vacuum} {
 | |
|       incr ::nRow
 | |
|       if {$::nRow == $::iWrite} {
 | |
|         db eval {
 | |
|           CREATE TABLE tbl1(a, b);
 | |
|           INSERT INTO tbl1 VALUES('hello', 'world');
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     list [expr {[file size test.db] / 1024}]
 | |
|   } {20}
 | |
| 
 | |
|   do_test incrvacuum-7.${::iWrite}.3 {
 | |
|     execsql {
 | |
|       SELECT * FROM tbl1;
 | |
|     }
 | |
|   } {hello world}
 | |
| 
 | |
|   if {$::nRow == $::iWrite} break
 | |
|   incr ::iWrite
 | |
| }
 | |
| 
 | |
| #---------------------------------------------------------------------
 | |
| # This test - incrvacuum-8.* - is to check that nothing goes wrong
 | |
| # with an incremental-vacuum if it is the first statement executed
 | |
| # after an existing database is opened.
 | |
| #
 | |
| # At one point, this would always return SQLITE_SCHEMA (which 
 | |
| # causes an infinite loop in tclsqlite.c if using the Tcl interface).
 | |
| #
 | |
| do_test incrvacuum-8.1 {
 | |
|   db close
 | |
|   sqlite3 db test.db
 | |
|   execsql {
 | |
|     PRAGMA incremental_vacuum(50);
 | |
|   }
 | |
| } {}
 | |
| 
 | |
| #---------------------------------------------------------------------
 | |
| # At one point this test case was causing an assert() to fail.
 | |
| #
 | |
| do_test incrvacuum-9.1 {
 | |
|   db close
 | |
|   forcedelete test.db test.db-journal
 | |
|   sqlite3 db test.db
 | |
| 
 | |
|   execsql {
 | |
|     PRAGMA auto_vacuum = 'incremental';
 | |
|     CREATE TABLE t1(a, b, c);
 | |
|     CREATE TABLE t2(a, b, c);
 | |
|     INSERT INTO t2 VALUES(randstr(500,500),randstr(500,500),randstr(500,500));
 | |
|     INSERT INTO t1 VALUES(1, 2, 3);
 | |
|     INSERT INTO t1 SELECT a||a, b||b, c||c FROM t1;
 | |
|     INSERT INTO t1 SELECT a||a, b||b, c||c FROM t1;
 | |
|     INSERT INTO t1 SELECT a||a, b||b, c||c FROM t1;
 | |
|     INSERT INTO t1 SELECT a||a, b||b, c||c FROM t1;
 | |
|     INSERT INTO t1 SELECT a||a, b||b, c||c FROM t1;
 | |
|     INSERT INTO t1 SELECT a||a, b||b, c||c FROM t1;
 | |
|     INSERT INTO t1 SELECT a||a, b||b, c||c FROM t1;
 | |
|     INSERT INTO t1 SELECT a||a, b||b, c||c FROM t1;
 | |
|   }
 | |
| } {}
 | |
| 
 | |
| do_test incrvacuum-9.2 {
 | |
|   execsql {
 | |
|     PRAGMA synchronous = 'OFF';
 | |
|     BEGIN;
 | |
|     UPDATE t1 SET a = a, b = b, c = c;
 | |
|     DROP TABLE t2;
 | |
|     PRAGMA incremental_vacuum(10);
 | |
|     ROLLBACK;
 | |
|   }
 | |
| } {}
 | |
| 
 | |
| do_test incrvacuum-9.3 {
 | |
|   execsql {
 | |
|     PRAGMA cache_size = 10;
 | |
|     BEGIN;
 | |
|     UPDATE t1 SET a = a, b = b, c = c;
 | |
|     DROP TABLE t2;
 | |
|     PRAGMA incremental_vacuum(10);
 | |
|     ROLLBACK;
 | |
|   }
 | |
| } {}
 | |
| 
 | |
| #---------------------------------------------------------------------
 | |
| # Test that the parameter to the incremental_vacuum pragma works. That
 | |
| # is, if the user executes "PRAGMA incremental_vacuum(N)", at most
 | |
| # N pages are vacuumed.
 | |
| #
 | |
| do_test incrvacuum-10.1 {
 | |
|   execsql {
 | |
|     DROP TABLE t1;
 | |
|     DROP TABLE t2;
 | |
|   }
 | |
|   expr [file size test.db] / 1024
 | |
| } {29}
 | |
| 
 | |
| do_test incrvacuum-10.2 {
 | |
|   execsql {
 | |
|     PRAGMA incremental_vacuum(1);
 | |
|   }
 | |
|   expr [file size test.db] / 1024
 | |
| } {28}
 | |
| 
 | |
| do_test incrvacuum-10.3 {
 | |
|   execsql {
 | |
|     PRAGMA incremental_vacuum(5);
 | |
|   }
 | |
|   expr [file size test.db] / 1024
 | |
| } {23}
 | |
| 
 | |
| do_test incrvacuum-10.4 {
 | |
|   execsql {
 | |
|     PRAGMA incremental_vacuum('1');
 | |
|   }
 | |
|   expr [file size test.db] / 1024
 | |
| } {22}
 | |
| 
 | |
| do_test incrvacuum-10.5 {
 | |
|   execsql {
 | |
|     PRAGMA incremental_vacuum("+3");
 | |
|   }
 | |
|   expr [file size test.db] / 1024
 | |
| } {19}
 | |
| 
 | |
| do_test incrvacuum-10.6 {
 | |
|   execsql {
 | |
|     PRAGMA incremental_vacuum = 1;
 | |
|   }
 | |
|   expr [file size test.db] / 1024
 | |
| } {18}
 | |
| 
 | |
| do_test incrvacuum-10.7 {
 | |
|   # Use a really big number as an argument to incremetal_vacuum. Should
 | |
|   # be interpreted as "free all possible space".
 | |
|   execsql {
 | |
|     PRAGMA incremental_vacuum(2147483649);
 | |
|   }
 | |
|   expr [file size test.db] / 1024
 | |
| } {1}
 | |
| 
 | |
| do_test incrvacuum-10.8 {
 | |
|   execsql {
 | |
|     CREATE TABLE t1(x);
 | |
|     INSERT INTO t1 VALUES(hex(randomblob(1000)));
 | |
|     DROP TABLE t1;
 | |
|   }
 | |
|   # A negative number means free all possible space.
 | |
|   execsql {
 | |
|     PRAGMA incremental_vacuum=-1;
 | |
|   }
 | |
|   expr [file size test.db] / 1024
 | |
| } {1}
 | |
| 
 | |
| #----------------------------------------------------------------
 | |
| # Test that if we set the auto_vacuum mode to 'incremental', then
 | |
| # create a database, thereafter that database defaults to incremental 
 | |
| # vacuum mode.
 | |
| #
 | |
| db close
 | |
| forcedelete test.db test.db-journal
 | |
| sqlite3 db test.db
 | |
| 
 | |
| ifcapable default_autovacuum {
 | |
|   do_test incrvacuum-11.1-av-dflt-on {
 | |
|     execsql {
 | |
|       PRAGMA auto_vacuum;
 | |
|     }
 | |
|   } $AUTOVACUUM
 | |
| } else {
 | |
|   do_test incrvacuum-11.1-av-dflt-off {
 | |
|     execsql {
 | |
|       PRAGMA auto_vacuum;
 | |
|     }
 | |
|   } {0}
 | |
| }
 | |
| do_test incrvacuum-11.2 {
 | |
|   execsql {
 | |
|     PRAGMA auto_vacuum = incremental;
 | |
|   }
 | |
| } {}
 | |
| do_test incrvacuum-11.3 {
 | |
|   execsql {
 | |
|     PRAGMA auto_vacuum;
 | |
|   }
 | |
| } {2}
 | |
| do_test incrvacuum-11.4 {
 | |
|   # The database has now been created.
 | |
|   expr {[file size test.db]>0}
 | |
| } {1}
 | |
| do_test incrvacuum-11.5 {
 | |
|   # Close and reopen the connection.
 | |
|   db close
 | |
|   sqlite3 db test.db
 | |
| 
 | |
|   # Test we are still in incremental vacuum mode.
 | |
|   execsql { PRAGMA auto_vacuum; }
 | |
| } {2}
 | |
| do_test incrvacuum-11.6 {
 | |
|   execsql {
 | |
|     PRAGMA auto_vacuum = 'full';
 | |
|     PRAGMA auto_vacuum;
 | |
|   }
 | |
| } {1}
 | |
| do_test incrvacuum-11.7 {
 | |
|   # Close and reopen the connection.
 | |
|   db close
 | |
|   sqlite3 db test.db
 | |
| 
 | |
|   # Test we are still in "full" auto-vacuum mode.
 | |
|   execsql { PRAGMA auto_vacuum; }
 | |
| } {1}
 | |
| 
 | |
| #----------------------------------------------------------------------
 | |
| # Special case: What happens if the database is locked when a "PRAGMA
 | |
| # auto_vacuum = XXX" statement is executed.
 | |
| #
 | |
| db close
 | |
| forcedelete test.db test.db-journal
 | |
| sqlite3 db test.db
 | |
| 
 | |
| do_test incrvacuum-12.1 {
 | |
|   execsql {
 | |
|     PRAGMA auto_vacuum = 1;
 | |
|   }
 | |
|   expr {[file size test.db]>0}
 | |
| } {1}
 | |
| 
 | |
| # Try to change the auto-vacuum from "full" to "incremental" while the
 | |
| # database is locked. Nothing should change.
 | |
| #
 | |
| do_test incrvacuum-12.2 {
 | |
|   sqlite3 db2 test.db
 | |
|   execsql { BEGIN EXCLUSIVE; } db2
 | |
|   catchsql { PRAGMA auto_vacuum = 2; }
 | |
| } {1 {database is locked}}
 | |
| 
 | |
| do_test incrvacuum-12.3 {
 | |
|   execsql { ROLLBACK; } db2
 | |
|   execsql { PRAGMA auto_vacuum }
 | |
| } {2}   ;# Still 2 because PRAGMA auto_vacuum setting held in case of vacuum
 | |
| do_test incrvacuum-12.4 {
 | |
|   db close
 | |
|   sqlite3 db test.db
 | |
|   execsql { PRAGMA auto_vacuum }
 | |
| } {1}   ;# Revert to 1 because the database file did not change
 | |
| 
 | |
| do_test incrvacuum-12.5 {
 | |
|   execsql { SELECT * FROM sqlite_master }
 | |
|   execsql { PRAGMA auto_vacuum }
 | |
| } {1}
 | |
| 
 | |
| #----------------------------------------------------------------------
 | |
| # Special case #2: What if one process prepares a "PRAGMA auto_vacuum = XXX"
 | |
| # statement when the database is empty, but doesn't execute it until
 | |
| # after some other process has created the database.
 | |
| #
 | |
| db2 close
 | |
| db close
 | |
| forcedelete test.db test.db-journal
 | |
| sqlite3 db test.db  ;  set ::DB [sqlite3_connection_pointer db]
 | |
| sqlite3 db2 test.db
 | |
| 
 | |
| do_test incrvacuum-13.1 {
 | |
|   # File size is sometimes 1 instead of 0 due to the hack we put in
 | |
|   # to work around ticket #3260.  Search for comments on #3260 in
 | |
|   # os_unix.c.
 | |
|   expr {[file size test.db]>1}
 | |
| } {0}
 | |
| do_test incrvacuum-13.2 {
 | |
|   set ::STMT [sqlite3_prepare $::DB {PRAGMA auto_vacuum = 2} -1 DUMMY]
 | |
|   execsql {
 | |
|     PRAGMA auto_vacuum = none;
 | |
|     PRAGMA default_cache_size = 1024;
 | |
|     PRAGMA auto_vacuum;
 | |
|   } db2
 | |
| } {0}
 | |
| do_test incrvacuum-13.3 {
 | |
|   expr {[file size test.db]>0}
 | |
| } {1}
 | |
| do_test incrvacuum-13.4 {
 | |
|   set rc [sqlite3_step $::STMT]
 | |
|   list $rc [sqlite3_finalize $::STMT]
 | |
| } {SQLITE_DONE SQLITE_OK}
 | |
| do_test incrvacuum-13.5 {
 | |
|   execsql {
 | |
|     PRAGMA auto_vacuum;
 | |
|   }
 | |
| } {0}
 | |
| 
 | |
| 
 | |
| # Verify that the incremental_vacuum pragma fails gracefully if it
 | |
| # is used against an invalid database file.
 | |
| #
 | |
| if {[permutation] == ""} {
 | |
|   do_test incrvacuum-14.1 {
 | |
|     set out [open invalid.db w]
 | |
|     puts $out "This is not an SQLite database file"
 | |
|     close $out
 | |
|     sqlite3 db3 invalid.db
 | |
|     catchsql {
 | |
|       PRAGMA incremental_vacuum(10);
 | |
|     } db3
 | |
|   } {1 {file is encrypted or is not a database}}
 | |
|   db3 close
 | |
| }
 | |
| 
 | |
| do_test incrvacuum-15.1 {
 | |
|   db close
 | |
|   db2 close
 | |
|   forcedelete test.db
 | |
|   sqlite3 db test.db
 | |
| 
 | |
|   set str [string repeat "abcdefghij" 500]
 | |
| 
 | |
|   execsql {
 | |
|     PRAGMA cache_size = 10;
 | |
|     PRAGMA auto_vacuum = incremental;
 | |
|     CREATE TABLE t1(x, y);
 | |
|     INSERT INTO t1 VALUES('a', $str);
 | |
|     INSERT INTO t1 VALUES('b', $str);
 | |
|     INSERT INTO t1 VALUES('c', $str);
 | |
|     INSERT INTO t1 VALUES('d', $str);
 | |
|     INSERT INTO t1 VALUES('e', $str);
 | |
|     INSERT INTO t1 VALUES('f', $str);
 | |
|     INSERT INTO t1 VALUES('g', $str);
 | |
|     INSERT INTO t1 VALUES('h', $str);
 | |
|     INSERT INTO t1 VALUES('i', $str);
 | |
|     INSERT INTO t1 VALUES('j', $str);
 | |
|     INSERT INTO t1 VALUES('j', $str);
 | |
| 
 | |
|     CREATE TABLE t2(x PRIMARY KEY, y);
 | |
|     INSERT INTO t2 VALUES('a', $str);
 | |
|     INSERT INTO t2 VALUES('b', $str);
 | |
|     INSERT INTO t2 VALUES('c', $str);
 | |
|     INSERT INTO t2 VALUES('d', $str);
 | |
| 
 | |
|     BEGIN;
 | |
|       DELETE FROM t2;
 | |
|       PRAGMA incremental_vacuum;
 | |
|   }
 | |
| 
 | |
|   catchsql {INSERT INTO t2 SELECT * FROM t1}
 | |
| 
 | |
|   execsql { 
 | |
|     COMMIT;
 | |
|     PRAGMA integrity_check;
 | |
|   }
 | |
| } {ok}
 | |
| 
 | |
| finish_test
 | 
