# 2005 November 30
#
# 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.
#
#***********************************************************************
#
# $Id: malloc5.test,v 1.1 2005/12/19 14:18:12 danielk1977 Exp $

#---------------------------------------------------------------------------
# NOTES ON EXPECTED BEHAVIOUR
#
#---------------------------------------------------------------------------

set testdir [file dirname $argv0]
source $testdir/tester.tcl

do_test malloc5-1.1 {
  # Simplest possible test. Call [db release_memory] when there is exactly
  # one unused page in a single pager cache. This test case set's the 
  # value of the ::pgalloc variable, which is used in subsequent tests.
  #
  # Note: Even though executing this statement on an empty database 
  # modifies 2 pages (the root of sqlite_master and the new root page), 
  # the sqlite_master root (page 1) is never freed because the btree layer
  # retains a reference to it for the entire transaction. 
  execsql {
    BEGIN;
    CREATE TABLE abc(a, b, c);
  }
  set ::pgalloc [db release_memory]
  expr $::pgalloc > 0
} {1}
do_test malloc5-1.2 {
  # Test that the transaction started in the above test is still active.
  # Because the page freed had been written to, freeing it required a
  # journal sync and exclusive lock on the database file. Test the file
  # appears to be locked.
  sqlite3 db2 test.db
  catchsql {
    SELECT * FROM abc;
  } db2
} {1 {database is locked}}
do_test malloc5-1.3 {
  # Again call [db release_memory] when there is exactly one unused page 
  # in the cache. The same amount of memory is required, but no journal-sync
  # or exclusive lock should be established.
  execsql {
    COMMIT;
    BEGIN;
    SELECT * FROM abc;
  }
  db release_memory
} $::pgalloc
do_test malloc5-1.4 {
  # Database should not be locked this time.
  catchsql {
    SELECT * FROM abc;
  } db2
} {0 {}}
do_test malloc5-1.5 {
  # Manipulate the cache so that it contains two unused pages. One requires 
  # a journal-sync to free, the other does not.
  execsql {
    SELECT * FROM abc;
    CREATE TABLE def(d, e, f);
  }
  db release_memory 500
} $::pgalloc
do_test malloc5-1.6 {
  # Database should not be locked this time. The above test case only
  # requested 500 bytes of memory, which can be obtained by freeing the page
  # that does not require an fsync().
  catchsql {
    SELECT * FROM abc;
  } db2
} {0 {}}
do_test malloc5-1.7 {
  # Release another 500 bytes of memory. This time we require a sync(), 
  # so the database file will be locked afterwards.
  db release_memory 500
} $::pgalloc
do_test malloc5-1.8 {
  catchsql {
    SELECT * FROM abc;
  } db2
} {1 {database is locked}}
do_test malloc5-1.9 {
  execsql {
    COMMIT;
  }
} {}


do_test malloc5-2.1 {
  # Put some data in tables abc and def. Both tables are still wholly 
  # contained within their root pages.
  execsql {
    INSERT INTO abc VALUES(1, 2, 3);
    INSERT INTO abc VALUES(4, 5, 6);
    INSERT INTO def VALUES(7, 8, 9);
    INSERT INTO def VALUES(10,11,12);
  }
} {}
do_test malloc5-2.2 {
  # Load the root-page for table def into the cache. Then query table abc. 
  # Halfway through the query call sqlite3_release_memory(). The goal of this
  # test is to make sure we don't free pages that are in use (specifically, 
  # the root of table abc).
  set nRelease 0
  execsql { 
    BEGIN;
    SELECT * FROM def;
  }
  db eval {SELECT * FROM abc} {
    incr nRelease [db release_memory]
    lappend data $a $b $c
  }
  list $nRelease $data
} [list $pgalloc [list 1 2 3 4 5 6]]

finish_test


