
The root problem was that the sequence of BTree operations (Delete, Next) would not always leave the cursor pointing at the first entry after the entry that was deleted. A consequence of this error was that a DROP TABLE on a table with indices would not always remove every index associated with that table from the SQLITE_MASTER table. Subsequent attempts to open the database will fail when the index for the missing table was parsed. Changes have also been made to ignore extra indices in the SQLITE_MASTER table so that a database previously corrupted by this bug is once again readable. (CVS 316) FossilOrigin-Name: 8a984667113564f2bac7412165b6ff8b7e3e8f70
1019 lines
22 KiB
Plaintext
1019 lines
22 KiB
Plaintext
# 2001 September 15
|
|
#
|
|
# 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 script is btree database backend
|
|
#
|
|
# $Id: btree.test,v 1.11 2001/11/23 00:24:12 drh Exp $
|
|
|
|
|
|
set testdir [file dirname $argv0]
|
|
source $testdir/tester.tcl
|
|
|
|
if {[info commands btree_open]!=""} {
|
|
|
|
# Basic functionality. Open and close a database.
|
|
#
|
|
do_test btree-1.1 {
|
|
file delete -force test1.bt
|
|
file delete -force test1.bt-journal
|
|
set rc [catch {btree_open test1.bt} ::b1]
|
|
} {0}
|
|
|
|
# The second element of the list returned by btree_pager_stats is the
|
|
# number of pages currently checked out. We'll be checking this value
|
|
# frequently during this test script, to make sure the btree library
|
|
# is properly releasing the pages it checks out, and thus avoiding
|
|
# page leaks.
|
|
#
|
|
do_test btree-1.1.1 {
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {0}
|
|
do_test btree-1.2 {
|
|
set rc [catch {btree_open test1.bt} ::b2]
|
|
} {0}
|
|
do_test btree-1.3 {
|
|
set rc [catch {btree_close $::b2} msg]
|
|
lappend rc $msg
|
|
} {0 {}}
|
|
|
|
# Do an insert and verify that the database file grows in size.
|
|
#
|
|
do_test btree-1.4 {
|
|
set rc [catch {btree_begin_transaction $::b1} msg]
|
|
lappend rc $msg
|
|
} {0 {}}
|
|
do_test btree-1.4.1 {
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {1}
|
|
do_test btree-1.5 {
|
|
set rc [catch {btree_cursor $::b1 2 1} ::c1]
|
|
if {$rc} {lappend rc $::c1}
|
|
set rc
|
|
} {0}
|
|
do_test btree-1.6 {
|
|
set rc [catch {btree_insert $::c1 one 1.00} msg]
|
|
lappend rc $msg
|
|
} {0 {}}
|
|
do_test btree-1.7 {
|
|
btree_key $::c1
|
|
} {one}
|
|
do_test btree-1.8 {
|
|
btree_data $::c1
|
|
} {1.00}
|
|
do_test btree-1.9 {
|
|
set rc [catch {btree_close_cursor $::c1} msg]
|
|
lappend rc $msg
|
|
} {0 {}}
|
|
do_test btree-1.10 {
|
|
set rc [catch {btree_commit $::b1} msg]
|
|
lappend rc $msg
|
|
} {0 {}}
|
|
do_test btree-1.11 {
|
|
file size test1.bt
|
|
} {2048}
|
|
do_test btree-1.12 {
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {0}
|
|
|
|
# Reopen the database and attempt to read the record that we wrote.
|
|
#
|
|
do_test btree-2.1 {
|
|
set rc [catch {btree_cursor $::b1 2 1} ::c1]
|
|
if {$rc} {lappend rc $::c1}
|
|
set rc
|
|
} {0}
|
|
do_test btree-2.2 {
|
|
btree_move_to $::c1 abc
|
|
} {1}
|
|
do_test btree-2.3 {
|
|
btree_move_to $::c1 xyz
|
|
} {-1}
|
|
do_test btree-2.4 {
|
|
btree_move_to $::c1 one
|
|
} {0}
|
|
do_test btree-2.5 {
|
|
btree_key $::c1
|
|
} {one}
|
|
do_test btree-2.6 {
|
|
btree_data $::c1
|
|
} {1.00}
|
|
do_test btree-2.7 {
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {2}
|
|
|
|
# Do some additional inserts
|
|
#
|
|
do_test btree-3.1 {
|
|
btree_begin_transaction $::b1
|
|
btree_insert $::c1 two 2.00
|
|
btree_key $::c1
|
|
} {two}
|
|
do_test btree-3.1.1 {
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {2}
|
|
do_test btree-3.2 {
|
|
btree_insert $::c1 three 3.00
|
|
btree_key $::c1
|
|
} {three}
|
|
do_test btree-3.4 {
|
|
btree_insert $::c1 four 4.00
|
|
btree_key $::c1
|
|
} {four}
|
|
do_test btree-3.5 {
|
|
btree_insert $::c1 five 5.00
|
|
btree_key $::c1
|
|
} {five}
|
|
do_test btree-3.6 {
|
|
btree_insert $::c1 six 6.00
|
|
btree_key $::c1
|
|
} {six}
|
|
#btree_page_dump $::b1 2
|
|
do_test btree-3.7 {
|
|
set rc [btree_move_to $::c1 {}]
|
|
expr {$rc>0}
|
|
} {1}
|
|
do_test btree-3.8 {
|
|
btree_key $::c1
|
|
} {five}
|
|
do_test btree-3.9 {
|
|
btree_data $::c1
|
|
} {5.00}
|
|
do_test btree-3.10 {
|
|
btree_next $::c1
|
|
btree_key $::c1
|
|
} {four}
|
|
do_test btree-3.11 {
|
|
btree_data $::c1
|
|
} {4.00}
|
|
do_test btree-3.12 {
|
|
btree_next $::c1
|
|
btree_key $::c1
|
|
} {one}
|
|
do_test btree-3.13 {
|
|
btree_data $::c1
|
|
} {1.00}
|
|
do_test btree-3.14 {
|
|
btree_next $::c1
|
|
btree_key $::c1
|
|
} {six}
|
|
do_test btree-3.15 {
|
|
btree_data $::c1
|
|
} {6.00}
|
|
do_test btree-3.16 {
|
|
btree_next $::c1
|
|
btree_key $::c1
|
|
} {three}
|
|
do_test btree-3.17 {
|
|
btree_data $::c1
|
|
} {3.00}
|
|
do_test btree-3.18 {
|
|
btree_next $::c1
|
|
btree_key $::c1
|
|
} {two}
|
|
do_test btree-3.19 {
|
|
btree_data $::c1
|
|
} {2.00}
|
|
do_test btree-3.20 {
|
|
btree_next $::c1
|
|
btree_key $::c1
|
|
} {}
|
|
do_test btree-3.21 {
|
|
btree_data $::c1
|
|
} {}
|
|
|
|
# Commit the changes, reopen and reread the data
|
|
#
|
|
do_test btree-3.22 {
|
|
set rc [catch {btree_close_cursor $::c1} msg]
|
|
lappend rc $msg
|
|
} {0 {}}
|
|
do_test btree-3.22.1 {
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {1}
|
|
do_test btree-3.23 {
|
|
set rc [catch {btree_commit $::b1} msg]
|
|
lappend rc $msg
|
|
} {0 {}}
|
|
do_test btree-3.23.1 {
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {0}
|
|
do_test btree-3.24 {
|
|
file size test1.bt
|
|
} {2048}
|
|
do_test btree-3.25 {
|
|
set rc [catch {btree_cursor $::b1 2 1} ::c1]
|
|
if {$rc} {lappend rc $::c1}
|
|
set rc
|
|
} {0}
|
|
do_test btree-3.25.1 {
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {2}
|
|
do_test btree-3.26 {
|
|
set rc [btree_move_to $::c1 {}]
|
|
expr {$rc>0}
|
|
} {1}
|
|
do_test btree-3.27 {
|
|
btree_key $::c1
|
|
} {five}
|
|
do_test btree-3.28 {
|
|
btree_data $::c1
|
|
} {5.00}
|
|
do_test btree-3.29 {
|
|
btree_next $::c1
|
|
btree_key $::c1
|
|
} {four}
|
|
do_test btree-3.30 {
|
|
btree_data $::c1
|
|
} {4.00}
|
|
do_test btree-3.31 {
|
|
btree_next $::c1
|
|
btree_key $::c1
|
|
} {one}
|
|
do_test btree-3.32 {
|
|
btree_data $::c1
|
|
} {1.00}
|
|
do_test btree-3.33 {
|
|
btree_next $::c1
|
|
btree_key $::c1
|
|
} {six}
|
|
do_test btree-3.34 {
|
|
btree_data $::c1
|
|
} {6.00}
|
|
do_test btree-3.35 {
|
|
btree_next $::c1
|
|
btree_key $::c1
|
|
} {three}
|
|
do_test btree-3.36 {
|
|
btree_data $::c1
|
|
} {3.00}
|
|
do_test btree-3.37 {
|
|
btree_next $::c1
|
|
btree_key $::c1
|
|
} {two}
|
|
do_test btree-3.38 {
|
|
btree_data $::c1
|
|
} {2.00}
|
|
do_test btree-3.39 {
|
|
btree_next $::c1
|
|
btree_key $::c1
|
|
} {}
|
|
do_test btree-3.40 {
|
|
btree_data $::c1
|
|
} {}
|
|
do_test btree-3.41 {
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {2}
|
|
|
|
|
|
# Now try a delete
|
|
#
|
|
do_test btree-4.1 {
|
|
btree_begin_transaction $::b1
|
|
btree_move_to $::c1 one
|
|
btree_key $::c1
|
|
} {one}
|
|
do_test btree-4.1.1 {
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {2}
|
|
do_test btree-4.2 {
|
|
btree_delete $::c1
|
|
} {}
|
|
do_test btree-4.3 {
|
|
btree_key $::c1
|
|
} {six}
|
|
do_test btree-4.4 {
|
|
btree_next $::c1
|
|
btree_key $::c1
|
|
} {six}
|
|
do_test btree-4.5 {
|
|
btree_next $::c1
|
|
btree_key $::c1
|
|
} {three}
|
|
do_test btree-4.4 {
|
|
btree_move_to $::c1 {}
|
|
set r {}
|
|
while 1 {
|
|
set key [btree_key $::c1]
|
|
if {$key==""} break
|
|
lappend r $key
|
|
lappend r [btree_data $::c1]
|
|
btree_next $::c1
|
|
}
|
|
set r
|
|
} {five 5.00 four 4.00 six 6.00 three 3.00 two 2.00}
|
|
|
|
# Commit and make sure the delete is still there.
|
|
#
|
|
do_test btree-4.5 {
|
|
btree_commit $::b1
|
|
btree_move_to $::c1 {}
|
|
set r {}
|
|
while 1 {
|
|
set key [btree_key $::c1]
|
|
if {$key==""} break
|
|
lappend r $key
|
|
lappend r [btree_data $::c1]
|
|
btree_next $::c1
|
|
}
|
|
set r
|
|
} {five 5.00 four 4.00 six 6.00 three 3.00 two 2.00}
|
|
|
|
# Completely close the database and reopen it. Then check
|
|
# the data again.
|
|
#
|
|
do_test btree-4.6 {
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {2}
|
|
do_test btree-4.7 {
|
|
btree_close_cursor $::c1
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {0}
|
|
do_test btree-4.8 {
|
|
btree_close $::b1
|
|
set ::b1 [btree_open test1.bt]
|
|
set ::c1 [btree_cursor $::b1 2 1]
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {2}
|
|
do_test btree-4.9 {
|
|
set r {}
|
|
while 1 {
|
|
set key [btree_key $::c1]
|
|
if {$key==""} break
|
|
lappend r $key
|
|
lappend r [btree_data $::c1]
|
|
btree_next $::c1
|
|
}
|
|
set r
|
|
} {five 5.00 four 4.00 six 6.00 three 3.00 two 2.00}
|
|
|
|
# Try to read and write meta data
|
|
#
|
|
do_test btree-5.1 {
|
|
btree_get_meta $::b1
|
|
} {0 0 0 0}
|
|
do_test btree-5.2 {
|
|
set rc [catch {btree_update_meta $::b1 1 2 3 4} msg]
|
|
lappend rc $msg
|
|
} {1 SQLITE_ERROR}
|
|
do_test btree-5.3 {
|
|
btree_begin_transaction $::b1
|
|
set rc [catch {btree_update_meta $::b1 1 2 3 4} msg]
|
|
lappend rc $msg
|
|
} {0 {}}
|
|
do_test btree-5.4 {
|
|
btree_get_meta $::b1
|
|
} {0 2 3 4}
|
|
do_test btree-5.5 {
|
|
btree_close_cursor $::c1
|
|
btree_rollback $::b1
|
|
btree_get_meta $::b1
|
|
} {0 0 0 0}
|
|
do_test btree-5.6 {
|
|
btree_begin_transaction $::b1
|
|
btree_update_meta $::b1 999 10 20 30
|
|
btree_commit $::b1
|
|
btree_get_meta $::b1
|
|
} {0 10 20 30}
|
|
|
|
proc select_all {cursor} {
|
|
set r {}
|
|
btree_move_to $cursor {}
|
|
while 1 {
|
|
set key [btree_key $cursor]
|
|
if {$key==""} break
|
|
lappend r $key
|
|
lappend r [btree_data $cursor]
|
|
btree_next $cursor
|
|
}
|
|
return $r
|
|
}
|
|
proc select_keys {cursor} {
|
|
set r {}
|
|
btree_move_to $cursor {}
|
|
while 1 {
|
|
set key [btree_key $cursor]
|
|
if {$key==""} break
|
|
lappend r $key
|
|
btree_next $cursor
|
|
}
|
|
return $r
|
|
}
|
|
|
|
# Try to create a new table in the database file
|
|
#
|
|
do_test btree-6.1 {
|
|
set rc [catch {btree_create_table $::b1} msg]
|
|
lappend rc $msg
|
|
} {1 SQLITE_ERROR}
|
|
do_test btree-6.2 {
|
|
btree_begin_transaction $::b1
|
|
set ::t2 [btree_create_table $::b1]
|
|
} {3}
|
|
do_test btree-6.2.1 {
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {1}
|
|
do_test btree-6.2.2 {
|
|
set ::c2 [btree_cursor $::b1 $::t2 1]
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {2}
|
|
do_test btree-6.2.3 {
|
|
btree_insert $::c2 ten 10
|
|
btree_key $::c2
|
|
} {ten}
|
|
do_test btree-6.3 {
|
|
btree_commit $::b1
|
|
set ::c1 [btree_cursor $::b1 2 1]
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {3}
|
|
do_test btree-6.3.1 {
|
|
select_all $::c1
|
|
} {five 5.00 four 4.00 six 6.00 three 3.00 two 2.00}
|
|
#btree_page_dump $::b1 3
|
|
do_test btree-6.4 {
|
|
select_all $::c2
|
|
} {ten 10}
|
|
|
|
# Drop the new table, then create it again anew.
|
|
#
|
|
do_test btree-6.5 {
|
|
btree_begin_transaction $::b1
|
|
} {}
|
|
do_test btree-6.6 {
|
|
btree_close_cursor $::c2
|
|
} {}
|
|
do_test btree-6.6.1 {
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {2}
|
|
do_test btree-6.7 {
|
|
btree_drop_table $::b1 $::t2
|
|
} {}
|
|
do_test btree-6.7.1 {
|
|
lindex [btree_get_meta $::b1] 0
|
|
} {1}
|
|
do_test btree-6.8 {
|
|
set ::t2 [btree_create_table $::b1]
|
|
} {3}
|
|
do_test btree-6.8.1 {
|
|
lindex [btree_get_meta $::b1] 0
|
|
} {0}
|
|
do_test btree-6.9 {
|
|
set ::c2 [btree_cursor $::b1 $::t2 1]
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {3}
|
|
|
|
do_test btree-6.9.1 {
|
|
btree_move_to $::c2 {}
|
|
btree_key $::c2
|
|
} {}
|
|
|
|
# If we drop table 2 it just clears the table. Table 2 always exists.
|
|
#
|
|
do_test btree-6.10 {
|
|
btree_close_cursor $::c1
|
|
btree_drop_table $::b1 2
|
|
set ::c1 [btree_cursor $::b1 2 1]
|
|
btree_move_to $::c1 {}
|
|
btree_key $::c1
|
|
} {}
|
|
do_test btree-6.11 {
|
|
btree_commit $::b1
|
|
select_all $::c1
|
|
} {}
|
|
do_test btree-6.12 {
|
|
select_all $::c2
|
|
} {}
|
|
do_test btree-6.13 {
|
|
btree_close_cursor $::c2
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {2}
|
|
|
|
# Check to see that pages defragment properly. To do this test we will
|
|
#
|
|
# 1. Fill the first page table 2 with data.
|
|
# 2. Delete every other entry of table 2.
|
|
# 3. Insert a single entry that requires more contiguous
|
|
# space than is available.
|
|
#
|
|
do_test btree-7.1 {
|
|
btree_begin_transaction $::b1
|
|
} {}
|
|
catch {unset key}
|
|
catch {unset data}
|
|
do_test btree-7.2 {
|
|
for {set i 0} {$i<36} {incr i} {
|
|
set key [format %03d $i]
|
|
set data "*** $key ***"
|
|
btree_insert $::c1 $key $data
|
|
}
|
|
lrange [btree_cursor_dump $::c1] 4 5
|
|
} {8 1}
|
|
do_test btree-7.3 {
|
|
btree_move_to $::c1 000
|
|
while {[btree_key $::c1]!=""} {
|
|
btree_delete $::c1
|
|
btree_next $::c1
|
|
btree_next $::c1
|
|
}
|
|
lrange [btree_cursor_dump $::c1] 4 5
|
|
} {512 19}
|
|
#btree_page_dump $::b1 2
|
|
do_test btree-7.4 {
|
|
btree_insert $::c1 018 {*** 018 ***+++}
|
|
btree_key $::c1
|
|
} {018}
|
|
do_test btree-7.5 {
|
|
lrange [btree_cursor_dump $::c1] 4 5
|
|
} {480 1}
|
|
#btree_page_dump $::b1 2
|
|
|
|
# Delete an entry to make a hole of a known size, then immediately recreate
|
|
# that entry. This tests the path into allocateSpace where the hole exactly
|
|
# matches the size of the desired space.
|
|
#
|
|
do_test btree-7.6 {
|
|
btree_move_to $::c1 007
|
|
btree_delete $::c1
|
|
btree_move_to $::c1 011
|
|
btree_delete $::c1
|
|
} {}
|
|
do_test btree-7.7 {
|
|
lindex [btree_cursor_dump $::c1] 5
|
|
} {3}
|
|
#btree_page_dump $::b1 2
|
|
do_test btree-7.8 {
|
|
btree_insert $::c1 007 {*** 007 ***}
|
|
lindex [btree_cursor_dump $::c1] 5
|
|
} {2}
|
|
#btree_page_dump $::b1 2
|
|
|
|
# Make sure the freeSpace() routine properly coaleses adjacent memory blocks
|
|
#
|
|
do_test btree-7.9 {
|
|
btree_move_to $::c1 013
|
|
btree_delete $::c1
|
|
lrange [btree_cursor_dump $::c1] 4 5
|
|
} {536 2}
|
|
do_test btree-7.10 {
|
|
btree_move_to $::c1 009
|
|
btree_delete $::c1
|
|
lrange [btree_cursor_dump $::c1] 4 5
|
|
} {564 2}
|
|
do_test btree-7.11 {
|
|
btree_move_to $::c1 018
|
|
btree_delete $::c1
|
|
lrange [btree_cursor_dump $::c1] 4 5
|
|
} {596 2}
|
|
do_test btree-7.13 {
|
|
btree_move_to $::c1 033
|
|
btree_delete $::c1
|
|
lrange [btree_cursor_dump $::c1] 4 5
|
|
} {624 3}
|
|
do_test btree-7.14 {
|
|
btree_move_to $::c1 035
|
|
btree_delete $::c1
|
|
lrange [btree_cursor_dump $::c1] 4 5
|
|
} {652 2}
|
|
#btree_page_dump $::b1 2
|
|
do_test btree-7.15 {
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {2}
|
|
|
|
# Check to see that data on overflow pages work correctly.
|
|
#
|
|
do_test btree-8.1 {
|
|
set data "*** This is a very long key "
|
|
while {[string length $data]<256} {append data $data}
|
|
set ::data $data
|
|
btree_insert $::c1 020 $data
|
|
} {}
|
|
#btree_page_dump $::b1 2
|
|
do_test btree-8.1.1 {
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {2}
|
|
#btree_pager_ref_dump $::b1
|
|
do_test btree-8.2 {
|
|
string length [btree_data $::c1]
|
|
} [string length $::data]
|
|
do_test btree-8.3 {
|
|
btree_data $::c1
|
|
} $::data
|
|
do_test btree-8.4 {
|
|
btree_delete $::c1
|
|
} {}
|
|
do_test btree-8.4.1 {
|
|
lindex [btree_get_meta $::b1] 0
|
|
} [expr {int(([string length $::data]-238+1019)/1020)}]
|
|
do_test btree-8.5 {
|
|
set data "*** This is an even longer key"
|
|
while {[string length $data]<2000} {append data $data}
|
|
set ::data $data
|
|
btree_insert $::c1 020 $data
|
|
} {}
|
|
do_test btree-8.6 {
|
|
string length [btree_data $::c1]
|
|
} [string length $::data]
|
|
do_test btree-8.7 {
|
|
btree_data $::c1
|
|
} $::data
|
|
do_test btree-8.8 {
|
|
btree_commit $::b1
|
|
btree_data $::c1
|
|
} $::data
|
|
do_test btree-8.9 {
|
|
btree_close_cursor $::c1
|
|
btree_close $::b1
|
|
set ::b1 [btree_open test1.bt]
|
|
set ::c1 [btree_cursor $::b1 2 1]
|
|
btree_move_to $::c1 020
|
|
btree_data $::c1
|
|
} $::data
|
|
do_test btree-8.10 {
|
|
btree_begin_transaction $::b1
|
|
btree_delete $::c1
|
|
} {}
|
|
do_test btree-8.11 {
|
|
lindex [btree_get_meta $::b1] 0
|
|
} [expr {int(([string length $::data]-238+1019)/1020)}]
|
|
|
|
# Now check out keys on overflow pages.
|
|
#
|
|
do_test btree-8.12 {
|
|
set ::keyprefix "This is a long prefix to a key "
|
|
while {[string length $::keyprefix]<256} {append ::keyprefix $::keyprefix}
|
|
btree_close_cursor $::c1
|
|
btree_drop_table $::b1 2
|
|
lindex [btree_get_meta $::b1] 0
|
|
} {4}
|
|
do_test btree-8.12.1 {
|
|
set ::c1 [btree_cursor $::b1 2 1]
|
|
btree_insert $::c1 ${::keyprefix}1 1
|
|
btree_data $::c1
|
|
} {1}
|
|
do_test btree-8.13 {
|
|
btree_key $::c1
|
|
} ${keyprefix}1
|
|
do_test btree-8.14 {
|
|
btree_insert $::c1 ${::keyprefix}2 2
|
|
btree_insert $::c1 ${::keyprefix}3 3
|
|
btree_key $::c1
|
|
} ${keyprefix}3
|
|
do_test btree-8.15 {
|
|
btree_move_to $::c1 ${::keyprefix}2
|
|
btree_data $::c1
|
|
} {2}
|
|
do_test btree-8.16 {
|
|
btree_move_to $::c1 ${::keyprefix}1
|
|
btree_data $::c1
|
|
} {1}
|
|
do_test btree-8.17 {
|
|
btree_move_to $::c1 ${::keyprefix}3
|
|
btree_data $::c1
|
|
} {3}
|
|
do_test btree-8.18 {
|
|
lindex [btree_get_meta $::b1] 0
|
|
} {1}
|
|
do_test btree-8.19 {
|
|
btree_move_to $::c1 ${::keyprefix}2
|
|
btree_key $::c1
|
|
} ${::keyprefix}2
|
|
#btree_page_dump $::b1 2
|
|
do_test btree-8.20 {
|
|
btree_delete $::c1
|
|
btree_next $::c1
|
|
btree_key $::c1
|
|
} ${::keyprefix}3
|
|
#btree_page_dump $::b1 2
|
|
do_test btree-8.21 {
|
|
lindex [btree_get_meta $::b1] 0
|
|
} {2}
|
|
do_test btree-8.22 {
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {2}
|
|
do_test btree-8.23 {
|
|
btree_close_cursor $::c1
|
|
btree_drop_table $::b1 2
|
|
set ::c1 [btree_cursor $::b1 2 1]
|
|
lindex [btree_get_meta $::b1] 0
|
|
} {4}
|
|
do_test btree-8.24 {
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {2}
|
|
#btree_pager_ref_dump $::b1
|
|
|
|
# Check page splitting logic
|
|
#
|
|
do_test btree-9.1 {
|
|
for {set i 1} {$i<=19} {incr i} {
|
|
set key [format %03d $i]
|
|
set data "*** $key *** $key *** $key *** $key ***"
|
|
btree_insert $::c1 $key $data
|
|
}
|
|
} {}
|
|
#btree_tree_dump $::b1 2
|
|
#btree_pager_ref_dump $::b1
|
|
#set pager_refinfo_enable 1
|
|
do_test btree-9.2 {
|
|
btree_insert $::c1 020 {*** 020 *** 020 *** 020 *** 020 ***}
|
|
select_keys $::c1
|
|
} {001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020}
|
|
#btree_page_dump $::b1 5
|
|
#btree_page_dump $::b1 2
|
|
#btree_page_dump $::b1 7
|
|
#btree_pager_ref_dump $::b1
|
|
#set pager_refinfo_enable 0
|
|
|
|
# The previous "select_keys" command left the cursor pointing at the root
|
|
# page. So there should only be two pages checked out. 2 (the root) and
|
|
# page 1.
|
|
do_test btree-9.2.1 {
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {2}
|
|
for {set i 1} {$i<=20} {incr i} {
|
|
do_test btree-9.3.$i.1 [subst {
|
|
btree_move_to $::c1 [format %03d $i]
|
|
btree_key $::c1
|
|
}] [format %03d $i]
|
|
do_test btree-9.3.$i.2 [subst {
|
|
btree_move_to $::c1 [format %03d $i]
|
|
string range \[btree_data $::c1\] 0 10
|
|
}] "*** [format %03d $i] ***"
|
|
}
|
|
do_test btree-9.4.1 {
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {3}
|
|
|
|
# Check the page joining logic.
|
|
#
|
|
#btree_page_dump $::b1 2
|
|
#btree_pager_ref_dump $::b1
|
|
do_test btree-9.4.2 {
|
|
btree_move_to $::c1 005
|
|
btree_delete $::c1
|
|
} {}
|
|
#btree_page_dump $::b1 2
|
|
for {set i 1} {$i<=19} {incr i} {
|
|
if {$i==5} continue
|
|
do_test btree-9.5.$i.1 [subst {
|
|
btree_move_to $::c1 [format %03d $i]
|
|
btree_key $::c1
|
|
}] [format %03d $i]
|
|
do_test btree-9.5.$i.2 [subst {
|
|
btree_move_to $::c1 [format %03d $i]
|
|
string range \[btree_data $::c1\] 0 10
|
|
}] "*** [format %03d $i] ***"
|
|
}
|
|
#btree_pager_ref_dump $::b1
|
|
do_test btree-9.6 {
|
|
btree_close_cursor $::c1
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {1}
|
|
do_test btree-9.7 {
|
|
btree_rollback $::b1
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {0}
|
|
|
|
# Create a tree of depth two. That is, there is a single divider entry
|
|
# on the root pages and two leaf pages. Then delete the divider entry
|
|
# see what happens.
|
|
#
|
|
do_test btree-10.1 {
|
|
btree_begin_transaction $::b1
|
|
btree_drop_table $::b1 2
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {1}
|
|
do_test btree-10.2 {
|
|
set ::c1 [btree_cursor $::b1 2 1]
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {2}
|
|
do_test btree-10.3 {
|
|
for {set i 1} {$i<=20} {incr i} {
|
|
set key [format %03d $i]
|
|
set data "*** $key *** $key *** $key *** $key ***"
|
|
btree_insert $::c1 $key $data
|
|
}
|
|
select_keys $::c1
|
|
} {001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020}
|
|
#btree_page_dump $::b1 7
|
|
#btree_page_dump $::b1 2
|
|
#btree_page_dump $::b1 6
|
|
do_test btree-10.4 {
|
|
btree_move_to $::c1 011
|
|
btree_delete $::c1
|
|
select_keys $::c1
|
|
} {001 002 003 004 005 006 007 008 009 010 012 013 014 015 016 017 018 019 020}
|
|
#btree_tree_dump $::b1 2
|
|
#btree_pager_ref_dump $::b1
|
|
for {set i 1} {$i<=20} {incr i} {
|
|
do_test btree-10.5.$i {
|
|
btree_move_to $::c1 [format %03d $i]
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {2}
|
|
#btree_pager_ref_dump $::b1
|
|
#btree_tree_dump $::b1 2
|
|
}
|
|
|
|
# Create a tree with lots more pages
|
|
#
|
|
catch {unset ::data}
|
|
catch {unset ::key}
|
|
for {set i 21} {$i<=1000} {incr i} {
|
|
do_test btree-11.1.$i.1 {
|
|
set key [format %03d $i]
|
|
set ::data "*** $key *** $key *** $key *** $key ***"
|
|
btree_insert $::c1 $key $data
|
|
btree_key $::c1
|
|
} [format %03d $i]
|
|
do_test btree-11.1.$i.2 {
|
|
btree_data $::c1
|
|
} $::data
|
|
set ::key [format %03d [expr {$i/2}]]
|
|
if {$::key=="011"} {set ::key 010}
|
|
do_test btree-11.1.$i.3 {
|
|
btree_move_to $::c1 $::key
|
|
btree_key $::c1
|
|
} $::key
|
|
}
|
|
catch {unset ::data}
|
|
catch {unset ::key}
|
|
|
|
# Make sure our reference count is still correct.
|
|
#
|
|
do_test btree-11.2 {
|
|
btree_close_cursor $::c1
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {1}
|
|
do_test btree-11.3 {
|
|
set ::c1 [btree_cursor $::b1 2 1]
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {2}
|
|
#btree_page_dump $::b1 2
|
|
|
|
# Delete the dividers on the root page
|
|
#
|
|
do_test btree-11.4 {
|
|
btree_move_to $::c1 257
|
|
btree_delete $::c1
|
|
btree_next $::c1
|
|
btree_key $::c1
|
|
} {258}
|
|
do_test btree-11.4.1 {
|
|
btree_move_to $::c1 256
|
|
btree_key $::c1
|
|
} {256}
|
|
do_test btree-11.4.2 {
|
|
btree_move_to $::c1 258
|
|
btree_key $::c1
|
|
} {258}
|
|
do_test btree-11.4.3 {
|
|
btree_move_to $::c1 259
|
|
btree_key $::c1
|
|
} {259}
|
|
do_test btree-11.4.4 {
|
|
btree_move_to $::c1 257
|
|
set n [btree_key $::c1]
|
|
expr {$n==256||$n==258}
|
|
} {1}
|
|
do_test btree-11.5 {
|
|
btree_move_to $::c1 513
|
|
btree_delete $::c1
|
|
btree_next $::c1
|
|
btree_key $::c1
|
|
} {514}
|
|
do_test btree-11.5.1 {
|
|
btree_move_to $::c1 512
|
|
btree_key $::c1
|
|
} {512}
|
|
do_test btree-11.5.2 {
|
|
btree_move_to $::c1 514
|
|
btree_key $::c1
|
|
} {514}
|
|
do_test btree-11.5.3 {
|
|
btree_move_to $::c1 515
|
|
btree_key $::c1
|
|
} {515}
|
|
do_test btree-11.5.4 {
|
|
btree_move_to $::c1 513
|
|
set n [btree_key $::c1]
|
|
expr {$n==512||$n==514}
|
|
} {1}
|
|
do_test btree-11.6 {
|
|
btree_move_to $::c1 769
|
|
btree_delete $::c1
|
|
btree_next $::c1
|
|
btree_key $::c1
|
|
} {770}
|
|
do_test btree-11.6.1 {
|
|
btree_move_to $::c1 768
|
|
btree_key $::c1
|
|
} {768}
|
|
do_test btree-11.6.2 {
|
|
btree_move_to $::c1 771
|
|
btree_key $::c1
|
|
} {771}
|
|
do_test btree-11.6.3 {
|
|
btree_move_to $::c1 770
|
|
btree_key $::c1
|
|
} {770}
|
|
do_test btree-11.6.4 {
|
|
btree_move_to $::c1 769
|
|
set n [btree_key $::c1]
|
|
expr {$n==768||$n==770}
|
|
} {1}
|
|
#btree_page_dump $::b1 2
|
|
#btree_page_dump $::b1 25
|
|
|
|
# Change the data on an intermediate node such that the node becomes overfull
|
|
# and has to split. We happen to know that intermediate nodes exist on
|
|
# 337, 401 and 465 by the btree_page_dumps above
|
|
#
|
|
catch {unset ::data}
|
|
set ::data {This is going to be a very long data segment}
|
|
append ::data $::data
|
|
append ::data $::data
|
|
do_test btree-12.1 {
|
|
btree_insert $::c1 337 $::data
|
|
btree_data $::c1
|
|
} $::data
|
|
do_test btree-12.2 {
|
|
btree_insert $::c1 401 $::data
|
|
btree_data $::c1
|
|
} $::data
|
|
do_test btree-12.3 {
|
|
btree_insert $::c1 465 $::data
|
|
btree_data $::c1
|
|
} $::data
|
|
do_test btree-12.4 {
|
|
btree_move_to $::c1 337
|
|
btree_key $::c1
|
|
} {337}
|
|
do_test btree-12.5 {
|
|
btree_data $::c1
|
|
} $::data
|
|
do_test btree-12.6 {
|
|
btree_next $::c1
|
|
btree_key $::c1
|
|
} {338}
|
|
do_test btree-12.7 {
|
|
btree_move_to $::c1 464
|
|
btree_key $::c1
|
|
} {464}
|
|
do_test btree-12.8 {
|
|
btree_next $::c1
|
|
btree_data $::c1
|
|
} $::data
|
|
do_test btree-12.9 {
|
|
btree_next $::c1
|
|
btree_key $::c1
|
|
} {466}
|
|
do_test btree-12.10 {
|
|
btree_move_to $::c1 400
|
|
btree_key $::c1
|
|
} {400}
|
|
do_test btree-12.11 {
|
|
btree_next $::c1
|
|
btree_data $::c1
|
|
} $::data
|
|
do_test btree-12.12 {
|
|
btree_next $::c1
|
|
btree_key $::c1
|
|
} {402}
|
|
do_test btree-13.1 {
|
|
btree_sanity_check $::b1 2 3
|
|
} {}
|
|
|
|
# To Do:
|
|
#
|
|
# 1. Do some deletes from the 3-layer tree
|
|
# 2. Commit and reopen the database
|
|
# 3. Read every 15th entry and make sure it works
|
|
# 4. Implement btree_sanity and put it throughout this script
|
|
#
|
|
|
|
do_test btree-15.98 {
|
|
btree_close_cursor $::c1
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {1}
|
|
do_test btree-15.99 {
|
|
btree_rollback $::b1
|
|
lindex [btree_pager_stats $::b1] 1
|
|
} {0}
|
|
btree_pager_ref_dump $::b1
|
|
|
|
do_test btree-99.1 {
|
|
btree_close $::b1
|
|
} {}
|
|
catch {unset data}
|
|
catch {unset key}
|
|
|
|
} ;# end if( not mem: and has pager_open command );
|
|
|
|
finish_test
|