# 2007 Aug 13
#
# 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 tests aspects of the malloc failure while parsing
# CREATE TABLE statements in auto_vacuum mode.
#
# $Id: mallocC.test,v 1.9 2008/02/18 22:24:58 drh Exp $

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

# Only run these tests if memory debugging is turned on.
#
if {!$MEMDEBUG} {
   puts "Skipping mallocC tests: not compiled with -DSQLITE_MEMDEBUG..."
   finish_test
   return
}

proc do_mallocC_test {tn args} {
  array set ::mallocopts $args
  #set sum [allcksum db]

  for {set ::n 1} {true} {incr ::n} {

    # Run the SQL. Malloc number $::n is set to fail. A malloc() failure
    # may or may not be reported.
    sqlite3_memdebug_fail $::n -repeat 1
    do_test mallocC-$tn.$::n.1 {
      set res [catchsql [string trim $::mallocopts(-sql)]]
      set rc [expr { 
        0==[string compare $res {1 {out of memory}}] ||
        [db errorcode] == 3082 ||
        0==[lindex $res 0]
      }]
      if {$rc!=1} {
        puts "Error: $res"
      }
      set rc
    } {1}

    # If $::n is greater than the number of malloc() calls required to
    # execute the SQL, then this test is finished. Break out of the loop.
    set nFail [sqlite3_memdebug_fail -1]
    if {$nFail==0} {
      break
    }

    # Recover from the malloc failure.
    #
    # Update: The new malloc() failure handling means that a transaction may
    # still be active even if a malloc() has failed. But when these tests were
    # written this was not the case. So do a manual ROLLBACK here so that the
    # tests pass.
    do_test mallocC-$tn.$::n.2 {
      catch {
        execsql {
          ROLLBACK;
        }
      }
      expr 0
    } {0}

    # Checksum the database.
    #do_test mallocC-$tn.$::n.3 {
    #  allcksum db
    #} $sum

    #integrity_check mallocC-$tn.$::n.4
  if {$::nErr>1} return
  }
  unset ::mallocopts
}

sqlite3_extended_result_codes db 1

execsql {
  PRAGMA auto_vacuum=1;
  CREATE TABLE t0(a, b, c);
}
do_mallocC_test 1 -sql {
  BEGIN;
  -- Allocate 32 new root pages. This will exercise the 'extract specific 
  -- page from the freelist' code when in auto-vacuum mode (see the
  -- allocatePage() routine in btree.c).
  CREATE TABLE t1(a UNIQUE, b UNIQUE, c UNIQUE);
  CREATE TABLE t2(a UNIQUE, b UNIQUE, c UNIQUE);
  CREATE TABLE t3(a UNIQUE, b UNIQUE, c UNIQUE);
  CREATE TABLE t4(a UNIQUE, b UNIQUE, c UNIQUE);
  CREATE TABLE t5(a UNIQUE, b UNIQUE, c UNIQUE);
  CREATE TABLE t6(a UNIQUE, b UNIQUE, c UNIQUE);
  CREATE TABLE t7(a UNIQUE, b UNIQUE, c UNIQUE);
  CREATE TABLE t8(a UNIQUE, b UNIQUE, c UNIQUE);

  ROLLBACK;
}

finish_test
