xref: /sqlite-3.40.0/test/malloc3.test (revision b8fff29c)
11a485fcaSdanielk1977# 2005 November 30
21a485fcaSdanielk1977#
31a485fcaSdanielk1977# The author disclaims copyright to this source code.  In place of
41a485fcaSdanielk1977# a legal notice, here is a blessing:
51a485fcaSdanielk1977#
61a485fcaSdanielk1977#    May you do good and not evil.
71a485fcaSdanielk1977#    May you find forgiveness for yourself and forgive others.
81a485fcaSdanielk1977#    May you share freely, never taking more than you give.
91a485fcaSdanielk1977#
101a485fcaSdanielk1977#***********************************************************************
111a485fcaSdanielk1977#
1200fd957bSdanielk1977# This file contains tests to ensure that the library handles malloc() failures
1300fd957bSdanielk1977# correctly. The emphasis of these tests are the _prepare(), _step() and
1400fd957bSdanielk1977# _finalize() calls.
1500fd957bSdanielk1977#
167cd30bd3Sdrh# $Id: malloc3.test,v 1.24 2008/10/14 15:54:08 drh Exp $
171a485fcaSdanielk1977
181a485fcaSdanielk1977set testdir [file dirname $argv0]
191a485fcaSdanielk1977source $testdir/tester.tcl
20eee4c8caSdrhsource $testdir/malloc_common.tcl
211a485fcaSdanielk1977
221a485fcaSdanielk1977# Only run these tests if memory debugging is turned on.
23ed138fb3Sdrh#
24eee4c8caSdrhif {!$MEMDEBUG} {
255a3032b3Sdrh   puts "Skipping malloc3 tests: not compiled with -DSQLITE_MEMDEBUG..."
261a485fcaSdanielk1977   finish_test
271a485fcaSdanielk1977   return
281a485fcaSdanielk1977}
291a485fcaSdanielk1977
30*b8fff29cSdan# Do not run these tests if F2FS batch writes are supported. In this case,
31*b8fff29cSdan# it is possible for a single DML statement in an implicit transaction
32*b8fff29cSdan# to fail with SQLITE_NOMEM, but for the transaction to still end up
33*b8fff29cSdan# committed to disk. Which confuses the tests in this module.
34*b8fff29cSdan#
35*b8fff29cSdanif {[atomic_batch_write test.db]} {
36*b8fff29cSdan   puts "Skipping malloc3 tests: atomic-batch support"
37*b8fff29cSdan   finish_test
38*b8fff29cSdan   return
39*b8fff29cSdan}
40*b8fff29cSdan
41bac19cf9Sdan
42bac19cf9Sdan# Do not run these tests with an in-memory journal.
43bac19cf9Sdan#
44bac19cf9Sdan# In the pager layer, if an IO or OOM error occurs during a ROLLBACK, or
45bac19cf9Sdan# when flushing a page to disk due to cache-stress, the pager enters an
46bac19cf9Sdan# "error state". The only way out of the error state is to unlock the
47bac19cf9Sdan# database file and end the transaction, leaving whatever journal and
48bac19cf9Sdan# database files happen to be on disk in place. The next time the current
49bac19cf9Sdan# (or any other) connection opens a read transaction, hot-journal rollback
50bac19cf9Sdan# is performed if necessary.
51bac19cf9Sdan#
52bac19cf9Sdan# Of course, this doesn't work with an in-memory journal.
53bac19cf9Sdan#
54bac19cf9Sdanif {[permutation]=="inmemory_journal"} {
55bac19cf9Sdan  finish_test
56bac19cf9Sdan  return
57bac19cf9Sdan}
58bac19cf9Sdan
591a485fcaSdanielk1977#--------------------------------------------------------------------------
601a485fcaSdanielk1977# NOTES ON RECOVERING FROM A MALLOC FAILURE
611a485fcaSdanielk1977#
621a485fcaSdanielk1977# The tests in this file test the behaviours described in the following
631a485fcaSdanielk1977# paragraphs. These tests test the behaviour of the system when malloc() fails
641a485fcaSdanielk1977# inside of a call to _prepare(), _step(), _finalize() or _reset(). The
651a485fcaSdanielk1977# handling of malloc() failures within ancillary procedures is tested
661a485fcaSdanielk1977# elsewhere.
671a485fcaSdanielk1977#
681a485fcaSdanielk1977# Overview:
691a485fcaSdanielk1977#
701a485fcaSdanielk1977# Executing a statement is done in three stages (prepare, step and finalize). A
711a485fcaSdanielk1977# malloc() failure may occur within any stage. If a memory allocation fails
721a485fcaSdanielk1977# during statement preparation, no statement handle is returned. From the users
731a485fcaSdanielk1977# point of view the system state is as if _prepare() had never been called.
741a485fcaSdanielk1977#
751a485fcaSdanielk1977# If the memory allocation fails during the _step() or _finalize() calls, then
761a485fcaSdanielk1977# the database may be left in one of two states (after finalize() has been
771a485fcaSdanielk1977# called):
781a485fcaSdanielk1977#
791a485fcaSdanielk1977#     * As if the neither _step() nor _finalize() had ever been called on
801a485fcaSdanielk1977#       the statement handle (i.e. any changes made by the statement are
811a485fcaSdanielk1977#       rolled back).
821a485fcaSdanielk1977#     * The current transaction may be rolled back. In this case a hot-journal
831a485fcaSdanielk1977#       may or may not actually be present in the filesystem.
841a485fcaSdanielk1977#
851a485fcaSdanielk1977# The caller can tell the difference between these two scenarios by invoking
861a485fcaSdanielk1977# _get_autocommit().
871a485fcaSdanielk1977#
881a485fcaSdanielk1977#
891a485fcaSdanielk1977# Handling of sqlite3_reset():
901a485fcaSdanielk1977#
911a485fcaSdanielk1977# If a malloc() fails while executing an sqlite3_reset() call, this is handled
921a485fcaSdanielk1977# in the same way as a failure within _finalize(). The statement handle
931a485fcaSdanielk1977# is not deleted and must be passed to _finalize() for resource deallocation.
941a485fcaSdanielk1977# Attempting to _step() or _reset() the statement after a failed _reset() will
951a485fcaSdanielk1977# always return SQLITE_NOMEM.
961a485fcaSdanielk1977#
971a485fcaSdanielk1977#
981a485fcaSdanielk1977# Other active SQL statements:
991a485fcaSdanielk1977#
1001a485fcaSdanielk1977# The effect of a malloc failure on concurrently executing SQL statements,
1011a485fcaSdanielk1977# particularly when the statement is executing with READ_UNCOMMITTED set and
1021a485fcaSdanielk1977# the malloc() failure mandates statement rollback only. Currently, if
1031a485fcaSdanielk1977# transaction rollback is required, all other vdbe's are aborted.
1041a485fcaSdanielk1977#
1051a485fcaSdanielk1977#     Non-transient mallocs in btree.c:
1061a485fcaSdanielk1977#         * The Btree structure itself
1071a485fcaSdanielk1977#         * Each BtCursor structure
1081a485fcaSdanielk1977#
1091a485fcaSdanielk1977#     Mallocs in pager.c:
1101a485fcaSdanielk1977#         readMasterJournal()  - Space to read the master journal name
1111a485fcaSdanielk1977#         pager_delmaster()    - Space for the entire master journal file
1121a485fcaSdanielk1977#
1131a485fcaSdanielk1977#         sqlite3pager_open()  - The pager structure itself
1141a485fcaSdanielk1977#         sqlite3_pagerget()   - Space for a new page
1151a485fcaSdanielk1977#         pager_open_journal() - Pager.aInJournal[] bitmap
1161a485fcaSdanielk1977#         sqlite3pager_write() - For in-memory databases only: history page and
1171a485fcaSdanielk1977#                                statement history page.
1181a485fcaSdanielk1977#         pager_stmt_begin()   - Pager.aInStmt[] bitmap
1191a485fcaSdanielk1977#
1201a485fcaSdanielk1977# None of the above are a huge problem. The most troublesome failures are the
1211a485fcaSdanielk1977# transient malloc() calls in btree.c, which can occur during the tree-balance
1221a485fcaSdanielk1977# operation. This means the tree being balanced will be internally inconsistent
1231a485fcaSdanielk1977# after the malloc() fails. To avoid the corrupt tree being read by a
1241a485fcaSdanielk1977# READ_UNCOMMITTED query, we have to make sure the transaction or statement
1251a485fcaSdanielk1977# rollback occurs before sqlite3_step() returns, not during a subsequent
1261a485fcaSdanielk1977# sqlite3_finalize().
1271a485fcaSdanielk1977#--------------------------------------------------------------------------
1281a485fcaSdanielk1977
1291a485fcaSdanielk1977#--------------------------------------------------------------------------
1301a485fcaSdanielk1977# NOTES ON TEST IMPLEMENTATION
1311a485fcaSdanielk1977#
1321a485fcaSdanielk1977# The tests in this file are implemented differently from those in other
1331a485fcaSdanielk1977# files. Instead, tests are specified using three primitives: SQL, PREP and
1341a485fcaSdanielk1977# TEST. Each primitive has a single argument. Primitives are processed in
1351a485fcaSdanielk1977# the order they are specified in the file.
1361a485fcaSdanielk1977#
13785b623f2Sdrh# A TEST primitive specifies a TCL script as its argument. When a TEST
1381a485fcaSdanielk1977# directive is encountered the Tcl script is evaluated. Usually, this Tcl
1391a485fcaSdanielk1977# script contains one or more calls to [do_test].
1401a485fcaSdanielk1977#
14185b623f2Sdrh# A PREP primitive specifies an SQL script as its argument. When a PREP
1421a485fcaSdanielk1977# directive is encountered the SQL is evaluated using database connection
1431a485fcaSdanielk1977# [db].
1441a485fcaSdanielk1977#
1451a485fcaSdanielk1977# The SQL primitives are where the action happens. An SQL primitive must
14685b623f2Sdrh# contain a single, valid SQL statement as its argument. When an SQL
1471a485fcaSdanielk1977# primitive is encountered, it is evaluated one or more times to test the
1481a485fcaSdanielk1977# behaviour of the system when malloc() fails during preparation or
1491a485fcaSdanielk1977# execution of said statement. The Nth time the statement is executed,
1501a485fcaSdanielk1977# the Nth malloc is said to fail. The statement is executed until it
1511a485fcaSdanielk1977# succeeds, i.e. (M+1) times, where M is the number of mallocs() required
1521a485fcaSdanielk1977# to prepare and execute the statement.
1531a485fcaSdanielk1977#
1541a485fcaSdanielk1977# Each time an SQL statement fails, the driver program (see proc [run_test]
1551a485fcaSdanielk1977# below) figures out if a transaction has been automatically rolled back.
1561a485fcaSdanielk1977# If not, it executes any TEST block immediately proceeding the SQL
1571a485fcaSdanielk1977# statement, then reexecutes the SQL statement with the next value of N.
1581a485fcaSdanielk1977#
1591a485fcaSdanielk1977# If a transaction has been automatically rolled back, then the driver
1601a485fcaSdanielk1977# program executes all the SQL specified as part of SQL or PREP primitives
1611a485fcaSdanielk1977# between the current SQL statement and the most recent "BEGIN". Any
1621a485fcaSdanielk1977# TEST block immediately proceeding the SQL statement is evaluated, and
1631a485fcaSdanielk1977# then the SQL statement reexecuted with the incremented N value.
1641a485fcaSdanielk1977#
1651a485fcaSdanielk1977# That make any sense? If not, read the code in [run_test] and it might.
1661a485fcaSdanielk1977#
1671a485fcaSdanielk1977# Extra restriction imposed by the implementation:
1681a485fcaSdanielk1977#
1691a485fcaSdanielk1977# * If a PREP block starts a transaction, it must finish it.
1701a485fcaSdanielk1977# * A PREP block may not close a transaction it did not start.
1711a485fcaSdanielk1977#
1721a485fcaSdanielk1977#--------------------------------------------------------------------------
1731a485fcaSdanielk1977
1741a485fcaSdanielk1977
1751a485fcaSdanielk1977# These procs are used to build up a "program" in global variable
1761a485fcaSdanielk1977# ::run_test_script. At the end of this file, the proc [run_test] is used
1771a485fcaSdanielk1977# to execute the program (and all test cases contained therein).
1781a485fcaSdanielk1977#
179f44d4b41Smistachkinset ::run_test_sql_id 0
180da717982Sdanielk1977set ::run_test_script [list]
1811a485fcaSdanielk1977proc TEST {id t} {lappend ::run_test_script -test [list $id $t]}
1821a485fcaSdanielk1977proc PREP {p} {lappend ::run_test_script -prep [string trim $p]}
18393aed5a1Sdrhproc DEBUG {s} {lappend ::run_test_script -debug $s}
1841a485fcaSdanielk1977
1851a485fcaSdanielk1977# SQL --
1861a485fcaSdanielk1977#
1871a485fcaSdanielk1977#     SQL ?-norollback? <sql-text>
1881a485fcaSdanielk1977#
1891a485fcaSdanielk1977# Add an 'SQL' primitive to the program (see notes above). If the -norollback
1901a485fcaSdanielk1977# switch is present, then the statement is not allowed to automatically roll
1911a485fcaSdanielk1977# back any active transaction if malloc() fails. It must rollback the statement
1921a485fcaSdanielk1977# transaction only.
1931a485fcaSdanielk1977#
1941a485fcaSdanielk1977proc SQL  {a1 {a2 ""}} {
195f44d4b41Smistachkin  # An SQL primitive parameter is a list of three elements, an id, a boolean
196f44d4b41Smistachkin  # value indicating if the statement may cause transaction rollback when
197f44d4b41Smistachkin  # malloc() fails, and the sql statement itself.
198f44d4b41Smistachkin  set id [incr ::run_test_sql_id]
1991a485fcaSdanielk1977  if {$a2 == ""} {
200f44d4b41Smistachkin    lappend ::run_test_script -sql [list $id true [string trim $a1]]
2011a485fcaSdanielk1977  } else {
202f44d4b41Smistachkin    lappend ::run_test_script -sql [list $id false [string trim $a2]]
2031a485fcaSdanielk1977  }
2041a485fcaSdanielk1977}
2051a485fcaSdanielk1977
2061a485fcaSdanielk1977# TEST_AUTOCOMMIT --
2071a485fcaSdanielk1977#
2081a485fcaSdanielk1977#     A shorthand test to see if a transaction is active or not. The first
2091a485fcaSdanielk1977#     argument - $id - is the integer number of the test case. The second
2101a485fcaSdanielk1977#     argument is either 1 or 0, the expected value of the auto-commit flag.
2111a485fcaSdanielk1977#
2121a485fcaSdanielk1977proc TEST_AUTOCOMMIT {id a} {
21337f0d221Sdanielk1977    TEST $id "do_test \$testid { sqlite3_get_autocommit \$::DB } {$a}"
2141a485fcaSdanielk1977}
2151a485fcaSdanielk1977
2161a485fcaSdanielk1977#--------------------------------------------------------------------------
2171a485fcaSdanielk1977# Start of test program declaration
2181a485fcaSdanielk1977#
2191a485fcaSdanielk1977
2201a485fcaSdanielk1977
2211a485fcaSdanielk1977# Warm body test. A malloc() fails in the middle of a CREATE TABLE statement
2221a485fcaSdanielk1977# in a single-statement transaction on an empty database. Not too much can go
2231a485fcaSdanielk1977# wrong here.
2241a485fcaSdanielk1977#
2251a485fcaSdanielk1977TEST 1 {
2261a485fcaSdanielk1977  do_test $testid {
2271a485fcaSdanielk1977    execsql {SELECT tbl_name FROM sqlite_master;}
2281a485fcaSdanielk1977  } {}
2291a485fcaSdanielk1977}
2301a485fcaSdanielk1977SQL {
2317cd30bd3Sdrh  CREATE TABLE IF NOT EXISTS abc(a, b, c);
2321a485fcaSdanielk1977}
2331a485fcaSdanielk1977TEST 2 {
2341a485fcaSdanielk1977  do_test $testid.1 {
2351a485fcaSdanielk1977    execsql {SELECT tbl_name FROM sqlite_master;}
2361a485fcaSdanielk1977  } {abc}
2371a485fcaSdanielk1977}
2381a485fcaSdanielk1977
23985b623f2Sdrh# Insert a couple of rows into the table. each insert is in its own
2401a485fcaSdanielk1977# transaction. test that the table is unpopulated before running the inserts
2411a485fcaSdanielk1977# (and hence after each failure of the first insert), and that it has been
2421a485fcaSdanielk1977# populated correctly after the final insert succeeds.
2431a485fcaSdanielk1977#
2441a485fcaSdanielk1977TEST 3 {
2451a485fcaSdanielk1977  do_test $testid.2 {
2461a485fcaSdanielk1977    execsql {SELECT * FROM abc}
2471a485fcaSdanielk1977  } {}
2481a485fcaSdanielk1977}
2491a485fcaSdanielk1977SQL {INSERT INTO abc VALUES(1, 2, 3);}
2501a485fcaSdanielk1977SQL {INSERT INTO abc VALUES(4, 5, 6);}
2511a485fcaSdanielk1977SQL {INSERT INTO abc VALUES(7, 8, 9);}
2521a485fcaSdanielk1977TEST 4 {
2531a485fcaSdanielk1977  do_test $testid {
2541a485fcaSdanielk1977    execsql {SELECT * FROM abc}
2551a485fcaSdanielk1977  } {1 2 3 4 5 6 7 8 9}
2561a485fcaSdanielk1977}
2571a485fcaSdanielk1977
2581a485fcaSdanielk1977# Test a CREATE INDEX statement. Because the table 'abc' is so small, the index
2591a485fcaSdanielk1977# will all fit on a single page, so this doesn't test too much that the CREATE
2601a485fcaSdanielk1977# TABLE statement didn't test. A few of the transient malloc()s in btree.c
2611a485fcaSdanielk1977# perhaps.
2621a485fcaSdanielk1977#
2631a485fcaSdanielk1977SQL {CREATE INDEX abc_i ON abc(a, b, c);}
2641a485fcaSdanielk1977TEST 4 {
2651a485fcaSdanielk1977  do_test $testid {
2661a485fcaSdanielk1977    execsql {
2671a485fcaSdanielk1977      SELECT * FROM abc ORDER BY a DESC;
2681a485fcaSdanielk1977    }
2691a485fcaSdanielk1977  } {7 8 9 4 5 6 1 2 3}
2701a485fcaSdanielk1977}
2711a485fcaSdanielk1977
2721a485fcaSdanielk1977# Test a DELETE statement. Also create a trigger and a view, just to make sure
2731a485fcaSdanielk1977# these statements don't have any obvious malloc() related bugs in them. Note
2741a485fcaSdanielk1977# that the test above will be executed each time the DELETE fails, so we're
2751a485fcaSdanielk1977# also testing rollback of a DELETE from a table with an index on it.
2761a485fcaSdanielk1977#
2771a485fcaSdanielk1977SQL {DELETE FROM abc WHERE a > 2;}
2781a485fcaSdanielk1977SQL {CREATE TRIGGER abc_t AFTER INSERT ON abc BEGIN SELECT 'trigger!'; END;}
2791a485fcaSdanielk1977SQL {CREATE VIEW abc_v AS SELECT * FROM abc;}
2801a485fcaSdanielk1977TEST 5 {
2811a485fcaSdanielk1977  do_test $testid {
2821a485fcaSdanielk1977    execsql {
2831a485fcaSdanielk1977      SELECT name, tbl_name FROM sqlite_master ORDER BY name;
2841a485fcaSdanielk1977      SELECT * FROM abc;
2851a485fcaSdanielk1977    }
2861a485fcaSdanielk1977  } {abc abc abc_i abc abc_t abc abc_v abc_v 1 2 3}
2871a485fcaSdanielk1977}
2881a485fcaSdanielk1977
2891a485fcaSdanielk1977set sql {
2901a485fcaSdanielk1977  BEGIN;DELETE FROM abc;
2911a485fcaSdanielk1977}
292f44d4b41Smistachkinfor {set i 1} {$i < 100} {incr i} {
2931a485fcaSdanielk1977  set a $i
2941a485fcaSdanielk1977  set b "String value $i"
2951a485fcaSdanielk1977  set c [string repeat X $i]
2961a485fcaSdanielk1977  append sql "INSERT INTO abc VALUES ($a, '$b', '$c');"
2971a485fcaSdanielk1977}
2981a485fcaSdanielk1977append sql {COMMIT;}
2991a485fcaSdanielk1977PREP $sql
3001a485fcaSdanielk1977
3011a485fcaSdanielk1977SQL {
3021a485fcaSdanielk1977  DELETE FROM abc WHERE oid IN (SELECT oid FROM abc ORDER BY random() LIMIT 5);
3031a485fcaSdanielk1977}
3041a485fcaSdanielk1977TEST 6 {
3051a485fcaSdanielk1977  do_test $testid.1 {
3061a485fcaSdanielk1977    execsql {SELECT count(*) FROM abc}
3071a485fcaSdanielk1977  } {94}
3081a485fcaSdanielk1977  do_test $testid.2 {
3091a485fcaSdanielk1977    execsql {
3101a485fcaSdanielk1977      SELECT min(
3111a485fcaSdanielk1977          (oid == a) AND 'String value ' || a == b AND a == length(c)
3121a485fcaSdanielk1977      ) FROM abc;
3131a485fcaSdanielk1977    }
3141a485fcaSdanielk1977  } {1}
3151a485fcaSdanielk1977}
3161a485fcaSdanielk1977SQL {
3171a485fcaSdanielk1977  DELETE FROM abc WHERE oid IN (SELECT oid FROM abc ORDER BY random() LIMIT 5);
3181a485fcaSdanielk1977}
3191a485fcaSdanielk1977TEST 7 {
3201a485fcaSdanielk1977  do_test $testid {
3211a485fcaSdanielk1977    execsql {SELECT count(*) FROM abc}
3221a485fcaSdanielk1977  } {89}
3231a485fcaSdanielk1977  do_test $testid {
3241a485fcaSdanielk1977    execsql {
3251a485fcaSdanielk1977      SELECT min(
3261a485fcaSdanielk1977          (oid == a) AND 'String value ' || a == b AND a == length(c)
3271a485fcaSdanielk1977      ) FROM abc;
3281a485fcaSdanielk1977    }
3291a485fcaSdanielk1977  } {1}
3301a485fcaSdanielk1977}
3311a485fcaSdanielk1977SQL {
3321a485fcaSdanielk1977  DELETE FROM abc WHERE oid IN (SELECT oid FROM abc ORDER BY random() LIMIT 5);
3331a485fcaSdanielk1977}
3341a485fcaSdanielk1977TEST 9 {
3351a485fcaSdanielk1977  do_test $testid {
3361a485fcaSdanielk1977    execsql {SELECT count(*) FROM abc}
3371a485fcaSdanielk1977  } {84}
3381a485fcaSdanielk1977  do_test $testid {
3391a485fcaSdanielk1977    execsql {
3401a485fcaSdanielk1977      SELECT min(
3411a485fcaSdanielk1977          (oid == a) AND 'String value ' || a == b AND a == length(c)
3421a485fcaSdanielk1977      ) FROM abc;
3431a485fcaSdanielk1977    }
3441a485fcaSdanielk1977  } {1}
3451a485fcaSdanielk1977}
3461a485fcaSdanielk1977
3471a485fcaSdanielk1977set padding [string repeat X 500]
3481a485fcaSdanielk1977PREP [subst {
3491a485fcaSdanielk1977  DROP TABLE abc;
3501a485fcaSdanielk1977  CREATE TABLE abc(a PRIMARY KEY, padding, b, c);
3511a485fcaSdanielk1977  INSERT INTO abc VALUES(0, '$padding', 2, 2);
3521a485fcaSdanielk1977  INSERT INTO abc VALUES(3, '$padding', 5, 5);
3531a485fcaSdanielk1977  INSERT INTO abc VALUES(6, '$padding', 8, 8);
3541a485fcaSdanielk1977}]
3551a485fcaSdanielk1977
3561a485fcaSdanielk1977TEST 10 {
3571a485fcaSdanielk1977  do_test $testid {
3581a485fcaSdanielk1977    execsql {SELECT a, b, c FROM abc}
3591a485fcaSdanielk1977  } {0 2 2 3 5 5 6 8 8}
3601a485fcaSdanielk1977}
3611a485fcaSdanielk1977
3621a485fcaSdanielk1977SQL {BEGIN;}
3631a485fcaSdanielk1977SQL {INSERT INTO abc VALUES(9, 'XXXXX', 11, 12);}
3641a485fcaSdanielk1977TEST_AUTOCOMMIT 11 0
3651a485fcaSdanielk1977SQL -norollback {UPDATE abc SET a = a + 1, c = c + 1;}
3661a485fcaSdanielk1977TEST_AUTOCOMMIT 12 0
3671a485fcaSdanielk1977SQL {DELETE FROM abc WHERE a = 10;}
3681a485fcaSdanielk1977TEST_AUTOCOMMIT 13 0
3691a485fcaSdanielk1977SQL {COMMIT;}
3701a485fcaSdanielk1977
3711a485fcaSdanielk1977TEST 14 {
3721a485fcaSdanielk1977  do_test $testid.1 {
3731a485fcaSdanielk1977    sqlite3_get_autocommit $::DB
3741a485fcaSdanielk1977  } {1}
3751a485fcaSdanielk1977  do_test $testid.2 {
3761a485fcaSdanielk1977    execsql {SELECT a, b, c FROM abc}
3771a485fcaSdanielk1977  } {1 2 3 4 5 6 7 8 9}
3781a485fcaSdanielk1977}
3791a485fcaSdanielk1977
3801a485fcaSdanielk1977PREP [subst {
3811a485fcaSdanielk1977  DROP TABLE abc;
3821a485fcaSdanielk1977  CREATE TABLE abc(a, padding, b, c);
3831a485fcaSdanielk1977  INSERT INTO abc VALUES(1, '$padding', 2, 3);
3841a485fcaSdanielk1977  INSERT INTO abc VALUES(4, '$padding', 5, 6);
3851a485fcaSdanielk1977  INSERT INTO abc VALUES(7, '$padding', 8, 9);
3861a485fcaSdanielk1977  CREATE INDEX abc_i ON abc(a, padding, b, c);
3871a485fcaSdanielk1977}]
3881a485fcaSdanielk1977
3891a485fcaSdanielk1977TEST 15 {
3901a485fcaSdanielk1977  db eval {PRAGMA cache_size = 10}
3911a485fcaSdanielk1977}
3921a485fcaSdanielk1977
3931a485fcaSdanielk1977SQL {BEGIN;}
3941a485fcaSdanielk1977SQL -norllbck {INSERT INTO abc (oid, a, padding, b, c) SELECT NULL, * FROM abc}
3951a485fcaSdanielk1977TEST 16 {
3961a485fcaSdanielk1977  do_test $testid {
3971a485fcaSdanielk1977    execsql {SELECT a, count(*) FROM abc GROUP BY a;}
3981a485fcaSdanielk1977  } {1 2 4 2 7 2}
3991a485fcaSdanielk1977}
4001a485fcaSdanielk1977SQL -norllbck {INSERT INTO abc (oid, a, padding, b, c) SELECT NULL, * FROM abc}
4011a485fcaSdanielk1977TEST 17 {
4021a485fcaSdanielk1977  do_test $testid {
4031a485fcaSdanielk1977    execsql {SELECT a, count(*) FROM abc GROUP BY a;}
4041a485fcaSdanielk1977  } {1 4 4 4 7 4}
4051a485fcaSdanielk1977}
4061a485fcaSdanielk1977SQL -norllbck {INSERT INTO abc (oid, a, padding, b, c) SELECT NULL, * FROM abc}
4071a485fcaSdanielk1977TEST 18 {
4081a485fcaSdanielk1977  do_test $testid {
4091a485fcaSdanielk1977    execsql {SELECT a, count(*) FROM abc GROUP BY a;}
4101a485fcaSdanielk1977  } {1 8 4 8 7 8}
4111a485fcaSdanielk1977}
4121a485fcaSdanielk1977SQL -norllbck {INSERT INTO abc (oid, a, padding, b, c) SELECT NULL, * FROM abc}
4131a485fcaSdanielk1977TEST 19 {
4141a485fcaSdanielk1977  do_test $testid {
4151a485fcaSdanielk1977    execsql {SELECT a, count(*) FROM abc GROUP BY a;}
4161a485fcaSdanielk1977  } {1 16 4 16 7 16}
4171a485fcaSdanielk1977}
4181a485fcaSdanielk1977SQL {COMMIT;}
4191a485fcaSdanielk1977TEST 21 {
4201a485fcaSdanielk1977  do_test $testid {
4211a485fcaSdanielk1977    execsql {SELECT a, count(*) FROM abc GROUP BY a;}
4221a485fcaSdanielk1977  } {1 16 4 16 7 16}
4231a485fcaSdanielk1977}
4241a485fcaSdanielk1977
4251a485fcaSdanielk1977SQL {BEGIN;}
4261a485fcaSdanielk1977SQL {DELETE FROM abc WHERE oid %2}
4271a485fcaSdanielk1977TEST 22 {
4281a485fcaSdanielk1977  do_test $testid {
4291a485fcaSdanielk1977    execsql {SELECT a, count(*) FROM abc GROUP BY a;}
4301a485fcaSdanielk1977  } {1 8 4 8 7 8}
4311a485fcaSdanielk1977}
4321a485fcaSdanielk1977SQL {DELETE FROM abc}
4331a485fcaSdanielk1977TEST 23 {
4341a485fcaSdanielk1977  do_test $testid {
4351a485fcaSdanielk1977    execsql {SELECT * FROM abc}
4361a485fcaSdanielk1977  } {}
4371a485fcaSdanielk1977}
4381a485fcaSdanielk1977SQL {ROLLBACK;}
4391a485fcaSdanielk1977TEST 24 {
4401a485fcaSdanielk1977  do_test $testid {
4411a485fcaSdanielk1977    execsql {SELECT a, count(*) FROM abc GROUP BY a;}
4421a485fcaSdanielk1977  } {1 16 4 16 7 16}
4431a485fcaSdanielk1977}
4441a485fcaSdanielk1977
4451a485fcaSdanielk1977# Test some schema modifications inside of a transaction. These should all
4461a485fcaSdanielk1977# cause transaction rollback if they fail. Also query a view, to cover a bit
4471a485fcaSdanielk1977# more code.
4481a485fcaSdanielk1977#
4491a485fcaSdanielk1977PREP {DROP VIEW abc_v;}
4501a485fcaSdanielk1977TEST 25 {
4511a485fcaSdanielk1977  do_test $testid {
4521a485fcaSdanielk1977    execsql {
4531a485fcaSdanielk1977      SELECT name, tbl_name FROM sqlite_master;
4541a485fcaSdanielk1977    }
4551a485fcaSdanielk1977  } {abc abc abc_i abc}
4561a485fcaSdanielk1977}
4571a485fcaSdanielk1977SQL {BEGIN;}
4581a485fcaSdanielk1977SQL {CREATE TABLE def(d, e, f);}
4591a485fcaSdanielk1977SQL {CREATE TABLE ghi(g, h, i);}
4601a485fcaSdanielk1977TEST 26 {
4611a485fcaSdanielk1977  do_test $testid {
4621a485fcaSdanielk1977    execsql {
4631a485fcaSdanielk1977      SELECT name, tbl_name FROM sqlite_master;
4641a485fcaSdanielk1977    }
4651a485fcaSdanielk1977  } {abc abc abc_i abc def def ghi ghi}
4661a485fcaSdanielk1977}
4671a485fcaSdanielk1977SQL {CREATE VIEW v1 AS SELECT * FROM def, ghi}
4681a485fcaSdanielk1977SQL {CREATE UNIQUE INDEX ghi_i1 ON ghi(g);}
4691a485fcaSdanielk1977TEST 27 {
4701a485fcaSdanielk1977  do_test $testid {
4711a485fcaSdanielk1977    execsql {
4721a485fcaSdanielk1977      SELECT name, tbl_name FROM sqlite_master;
4731a485fcaSdanielk1977    }
4741a485fcaSdanielk1977  } {abc abc abc_i abc def def ghi ghi v1 v1 ghi_i1 ghi}
4751a485fcaSdanielk1977}
4761a485fcaSdanielk1977SQL {INSERT INTO def VALUES('a', 'b', 'c')}
4771a485fcaSdanielk1977SQL {INSERT INTO def VALUES(1, 2, 3)}
4781a485fcaSdanielk1977SQL -norollback {INSERT INTO ghi SELECT * FROM def}
4791a485fcaSdanielk1977TEST 28 {
4801a485fcaSdanielk1977  do_test $testid {
4811a485fcaSdanielk1977    execsql {
4821a485fcaSdanielk1977      SELECT * FROM def, ghi WHERE d = g;
4831a485fcaSdanielk1977    }
4841a485fcaSdanielk1977  } {a b c a b c 1 2 3 1 2 3}
4851a485fcaSdanielk1977}
4861a485fcaSdanielk1977SQL {COMMIT}
4871a485fcaSdanielk1977TEST 29 {
4881a485fcaSdanielk1977  do_test $testid {
4891a485fcaSdanielk1977    execsql {
4901a485fcaSdanielk1977      SELECT * FROM v1 WHERE d = g;
4911a485fcaSdanielk1977    }
4921a485fcaSdanielk1977  } {a b c a b c 1 2 3 1 2 3}
4931a485fcaSdanielk1977}
4941a485fcaSdanielk1977
4951a485fcaSdanielk1977# Test a simple multi-file transaction
4961a485fcaSdanielk1977#
497fda06befSmistachkinforcedelete test2.db
4985a8f9374Sdanielk1977ifcapable attach {
499f4208043Sdanielk1977  SQL {ATTACH 'test2.db' AS aux;}
5001a485fcaSdanielk1977  SQL {BEGIN}
5011a485fcaSdanielk1977  SQL {CREATE TABLE aux.tbl2(x, y, z)}
5021a485fcaSdanielk1977  SQL {INSERT INTO tbl2 VALUES(1, 2, 3)}
5031a485fcaSdanielk1977  SQL {INSERT INTO def VALUES(4, 5, 6)}
5041a485fcaSdanielk1977  TEST 30 {
5051a485fcaSdanielk1977    do_test $testid {
5061a485fcaSdanielk1977      execsql {
5071a485fcaSdanielk1977        SELECT * FROM tbl2, def WHERE d = x;
5081a485fcaSdanielk1977      }
5091a485fcaSdanielk1977    } {1 2 3 1 2 3}
5101a485fcaSdanielk1977  }
5111a485fcaSdanielk1977  SQL {COMMIT}
5121a485fcaSdanielk1977  TEST 31 {
5131a485fcaSdanielk1977    do_test $testid {
5141a485fcaSdanielk1977      execsql {
5151a485fcaSdanielk1977        SELECT * FROM tbl2, def WHERE d = x;
5161a485fcaSdanielk1977      }
5171a485fcaSdanielk1977    } {1 2 3 1 2 3}
5181a485fcaSdanielk1977  }
5195a8f9374Sdanielk1977}
5201a485fcaSdanielk1977
52107cb560bSdanielk1977# Test what happens when a malloc() fails while there are other active
52207cb560bSdanielk1977# statements. This changes the way sqlite3VdbeHalt() works.
52307cb560bSdanielk1977TEST 32 {
52407cb560bSdanielk1977  if {![info exists ::STMT32]} {
52507cb560bSdanielk1977    set sql "SELECT name FROM sqlite_master"
52607cb560bSdanielk1977    set ::STMT32 [sqlite3_prepare $::DB $sql -1 DUMMY]
52707cb560bSdanielk1977    do_test $testid {
52807cb560bSdanielk1977      sqlite3_step $::STMT32
52907cb560bSdanielk1977    } {SQLITE_ROW}
53007cb560bSdanielk1977  }
53107cb560bSdanielk1977}
53297a227c9Sdanielk1977SQL BEGIN
53397a227c9Sdanielk1977TEST 33 {
53497a227c9Sdanielk1977  do_test $testid {
53597a227c9Sdanielk1977    execsql {SELECT * FROM ghi}
53697a227c9Sdanielk1977  } {a b c 1 2 3}
53707cb560bSdanielk1977}
53897a227c9Sdanielk1977SQL -norollback {
53997a227c9Sdanielk1977  -- There is a unique index on ghi(g), so this statement may not cause
54097a227c9Sdanielk1977  -- an automatic ROLLBACK. Hence the "-norollback" switch.
54197a227c9Sdanielk1977  INSERT INTO ghi SELECT '2'||g, h, i FROM ghi;
54297a227c9Sdanielk1977}
54397a227c9Sdanielk1977TEST 34 {
54497a227c9Sdanielk1977  if {[info exists ::STMT32]} {
54597a227c9Sdanielk1977    do_test $testid {
54697a227c9Sdanielk1977      sqlite3_finalize $::STMT32
54797a227c9Sdanielk1977    } {SQLITE_OK}
54897a227c9Sdanielk1977    unset ::STMT32
54997a227c9Sdanielk1977  }
55097a227c9Sdanielk1977}
55197a227c9Sdanielk1977SQL COMMIT
55207cb560bSdanielk1977
5531a485fcaSdanielk1977#
5541a485fcaSdanielk1977# End of test program declaration
5551a485fcaSdanielk1977#--------------------------------------------------------------------------
5561a485fcaSdanielk1977
55737f0d221Sdanielk1977proc run_test {arglist iRepeat {pcstart 0} {iFailStart 1}} {
5581a485fcaSdanielk1977  if {[llength $arglist] %2} {
5591a485fcaSdanielk1977    error "Uneven number of arguments to TEST"
5601a485fcaSdanielk1977  }
5611a485fcaSdanielk1977
5621a485fcaSdanielk1977  for {set i 0} {$i < $pcstart} {incr i} {
563f44d4b41Smistachkin    set k2 [lindex $arglist [expr {2 * $i}]]
564f44d4b41Smistachkin    set v2 [lindex $arglist [expr {2 * $i + 1}]]
5651a485fcaSdanielk1977    set ac [sqlite3_get_autocommit $::DB]        ;# Auto-Commit
5661a485fcaSdanielk1977    switch -- $k2 {
567f44d4b41Smistachkin      -sql  {db eval [lindex $v2 2]}
5681a485fcaSdanielk1977      -prep {db eval $v2}
569f44d4b41Smistachkin      -debug {eval $v2}
5701a485fcaSdanielk1977    }
5711a485fcaSdanielk1977    set nac [sqlite3_get_autocommit $::DB]       ;# New Auto-Commit
5721a485fcaSdanielk1977    if {$ac && !$nac} {set begin_pc $i}
5731a485fcaSdanielk1977  }
5741a485fcaSdanielk1977
575f3f06bb3Sdanielk1977  db rollback_hook [list incr ::rollback_hook_count]
576f3f06bb3Sdanielk1977
5771a485fcaSdanielk1977  set iFail $iFailStart
5781a485fcaSdanielk1977  set pc $pcstart
5791a485fcaSdanielk1977  while {$pc*2 < [llength $arglist]} {
580f44d4b41Smistachkin    # Fetch the current instruction type and payload.
581f44d4b41Smistachkin    set k [lindex $arglist [expr {2 * $pc}]]
582f44d4b41Smistachkin    set v [lindex $arglist [expr {2 * $pc + 1}]]
5831a485fcaSdanielk1977
5841a485fcaSdanielk1977    # Id of this iteration:
58593aed5a1Sdrh    set iterid "pc=$pc.iFail=$iFail$k"
5861a485fcaSdanielk1977
5871a485fcaSdanielk1977    switch -- $k {
5881a485fcaSdanielk1977
5891a485fcaSdanielk1977      -test {
5901a485fcaSdanielk1977        foreach {id script} $v {}
591f44d4b41Smistachkin        set testid "malloc3-(test $id).$iterid"
592f44d4b41Smistachkin        eval $script
5931a485fcaSdanielk1977        incr pc
5941a485fcaSdanielk1977      }
5951a485fcaSdanielk1977
5961a485fcaSdanielk1977      -sql {
597f3f06bb3Sdanielk1977        set ::rollback_hook_count 0
598f3f06bb3Sdanielk1977
599f44d4b41Smistachkin        set id [lindex $v 0]
600f44d4b41Smistachkin        set testid "malloc3-(integrity $id).$iterid"
601f44d4b41Smistachkin
6021a485fcaSdanielk1977        set ac [sqlite3_get_autocommit $::DB]        ;# Auto-Commit
60337f0d221Sdanielk1977        sqlite3_memdebug_fail $iFail -repeat 0
604f44d4b41Smistachkin        set rc [catch {db eval [lindex $v 2]} msg]   ;# True error occurs
6051a485fcaSdanielk1977        set nac [sqlite3_get_autocommit $::DB]       ;# New Auto-Commit
6061a485fcaSdanielk1977
607f3f06bb3Sdanielk1977        if {$rc != 0 && $nac && !$ac} {
608f3f06bb3Sdanielk1977          # Before [db eval] the auto-commit flag was clear. Now it
60948864df9Smistachkin          # is set. Since an error occurred we assume this was not a
61048864df9Smistachkin          # commit - therefore a rollback occurred. Check that the
611f3f06bb3Sdanielk1977          # rollback-hook was invoked.
612f44d4b41Smistachkin          do_test malloc3-rollback_hook_count.$iterid {
613f3f06bb3Sdanielk1977            set ::rollback_hook_count
614f3f06bb3Sdanielk1977          } {1}
615f3f06bb3Sdanielk1977        }
616f3f06bb3Sdanielk1977
617ae72d982Sdanielk1977        set nFail [sqlite3_memdebug_fail -1 -benigncnt nBenign]
6181a485fcaSdanielk1977        if {$rc == 0} {
619ae72d982Sdanielk1977            # Successful execution of sql. The number of failed malloc()
620ae72d982Sdanielk1977            # calls should be equal to the number of benign failures.
621ae72d982Sdanielk1977            # Otherwise a malloc() failed and the error was not reported.
622ae72d982Sdanielk1977            #
623f44d4b41Smistachkin            set expr {$nFail!=$nBenign}
624f44d4b41Smistachkin            if {[expr $expr]} {
625f44d4b41Smistachkin              error "Unreported malloc() failure, test \"$testid\", $expr"
6261a485fcaSdanielk1977            }
627f3f06bb3Sdanielk1977
6281a485fcaSdanielk1977            if {$ac && !$nac} {
629f3f06bb3Sdanielk1977              # Before the [db eval] the auto-commit flag was set, now it
630f3f06bb3Sdanielk1977              # is clear. We can deduce that a "BEGIN" statement has just
631f3f06bb3Sdanielk1977              # been successfully executed.
6321a485fcaSdanielk1977              set begin_pc $pc
6331a485fcaSdanielk1977            }
634f3f06bb3Sdanielk1977
6351a485fcaSdanielk1977            incr pc
6361a485fcaSdanielk1977            set iFail 1
637f44d4b41Smistachkin            integrity_check $testid
638ae72d982Sdanielk1977        } elseif {[regexp {.*out of memory} $msg] || [db errorcode] == 3082} {
639ae72d982Sdanielk1977            # Out of memory error, as expected.
640ae72d982Sdanielk1977            #
641f44d4b41Smistachkin            integrity_check $testid
6421a485fcaSdanielk1977            incr iFail
6431a485fcaSdanielk1977            if {$nac && !$ac} {
644f44d4b41Smistachkin              if {![lindex $v 1] && [db errorcode] != 3082} {
645f44d4b41Smistachkin                # error "Statement \"[lindex $v 2]\" caused a rollback"
6461a485fcaSdanielk1977              }
647f3f06bb3Sdanielk1977
6481a485fcaSdanielk1977              for {set i $begin_pc} {$i < $pc} {incr i} {
649f44d4b41Smistachkin                set k2 [lindex $arglist [expr {2 * $i}]]
650f44d4b41Smistachkin                set v2 [lindex $arglist [expr {2 * $i + 1}]]
6511a485fcaSdanielk1977                set catchupsql ""
6521a485fcaSdanielk1977                switch -- $k2 {
653f44d4b41Smistachkin                  -sql  {set catchupsql [lindex $v2 2]}
6541a485fcaSdanielk1977                  -prep {set catchupsql $v2}
6551a485fcaSdanielk1977                }
6561a485fcaSdanielk1977                db eval $catchupsql
6571a485fcaSdanielk1977              }
6581a485fcaSdanielk1977            }
6591a485fcaSdanielk1977        } else {
6601a485fcaSdanielk1977            error $msg
6611a485fcaSdanielk1977        }
6621a485fcaSdanielk1977
663f44d4b41Smistachkin        # back up to the previous "-test" block.
664f44d4b41Smistachkin        while {[lindex $arglist [expr {2 * ($pc - 1)}]] == "-test"} {
6651a485fcaSdanielk1977          incr pc -1
6661a485fcaSdanielk1977        }
6671a485fcaSdanielk1977      }
6681a485fcaSdanielk1977
6691a485fcaSdanielk1977      -prep {
6701a485fcaSdanielk1977        db eval $v
6711a485fcaSdanielk1977        incr pc
6721a485fcaSdanielk1977      }
6731a485fcaSdanielk1977
67493aed5a1Sdrh      -debug {
67593aed5a1Sdrh        eval $v
67693aed5a1Sdrh        incr pc
67793aed5a1Sdrh      }
67893aed5a1Sdrh
6791a485fcaSdanielk1977      default { error "Unknown switch: $k" }
6801a485fcaSdanielk1977    }
6811a485fcaSdanielk1977  }
6821a485fcaSdanielk1977}
6831a485fcaSdanielk1977
684f44d4b41Smistachkin# Turn off the Tcl interface's prepared statement caching facility. Then
68537f0d221Sdanielk1977# run the tests with "persistent" malloc failures.
686ae72d982Sdanielk1977sqlite3_extended_result_codes db 1
6871a485fcaSdanielk1977db cache size 0
68837f0d221Sdanielk1977run_test $::run_test_script 1
6891a485fcaSdanielk1977
69037f0d221Sdanielk1977# Close and reopen the db.
6912e588c75Sdanielk1977db close
692fda06befSmistachkinforcedelete test.db test.db-journal test2.db test2.db-journal
69337f0d221Sdanielk1977sqlite3 db test.db
694ae72d982Sdanielk1977sqlite3_extended_result_codes db 1
69537f0d221Sdanielk1977set ::DB [sqlite3_connection_pointer db]
6962e588c75Sdanielk1977
69796b958afSdan# Turn off the Tcl interface's prepared statement caching facility in
69837f0d221Sdanielk1977# the new connnection. Then run the tests with "transient" malloc failures.
69937f0d221Sdanielk1977db cache size 0
70037f0d221Sdanielk1977run_test $::run_test_script 0
70137f0d221Sdanielk1977
70237f0d221Sdanielk1977sqlite3_memdebug_fail -1
7031a485fcaSdanielk1977finish_test
704