1#
2# 2001 September 15
3#
4# The author disclaims copyright to this source code.  In place of
5# a legal notice, here is a blessing:
6#
7#    May you do good and not evil.
8#    May you find forgiveness for yourself and forgive others.
9#    May you share freely, never taking more than you give.
10#
11#***********************************************************************
12# This file implements regression tests for SQLite library.  The
13# focus of this script is btree database backend
14#
15# $Id: btree.test,v 1.15 2004/02/10 01:54:28 drh Exp $
16
17
18set testdir [file dirname $argv0]
19source $testdir/tester.tcl
20
21if {[info commands btree_open]!="" && $SQLITE_PAGE_SIZE==1024
22     && $SQLITE_USABLE_SIZE==1024} {
23
24# Basic functionality.  Open and close a database.
25#
26do_test btree-1.1 {
27  file delete -force test1.bt
28  file delete -force test1.bt-journal
29  set rc [catch {btree_open test1.bt} ::b1]
30} {0}
31
32# The second element of the list returned by btree_pager_stats is the
33# number of pages currently checked out.  We'll be checking this value
34# frequently during this test script, to make sure the btree library
35# is properly releasing the pages it checks out, and thus avoiding
36# page leaks.
37#
38do_test btree-1.1.1 {
39  lindex [btree_pager_stats $::b1] 1
40} {0}
41do_test btree-1.2 {
42  set rc [catch {btree_open test1.bt} ::b2]
43} {0}
44do_test btree-1.3 {
45  set rc [catch {btree_close $::b2} msg]
46  lappend rc $msg
47} {0 {}}
48
49# Do an insert and verify that the database file grows in size.
50#
51do_test btree-1.4 {
52  set rc [catch {btree_begin_transaction $::b1} msg]
53  lappend rc $msg
54} {0 {}}
55do_test btree-1.4.1 {
56  lindex [btree_pager_stats $::b1] 1
57} {1}
58do_test btree-1.5 {
59  set rc [catch {btree_cursor $::b1 2 1} ::c1]
60  if {$rc} {lappend rc $::c1}
61  set rc
62} {0}
63do_test btree-1.6 {
64  set rc [catch {btree_insert $::c1 one 1.00} msg]
65  lappend rc $msg
66} {0 {}}
67do_test btree-1.7 {
68  btree_key $::c1
69} {one}
70do_test btree-1.8 {
71  btree_data $::c1
72} {1.00}
73do_test btree-1.9 {
74  set rc [catch {btree_close_cursor $::c1} msg]
75  lappend rc $msg
76} {0 {}}
77do_test btree-1.10 {
78  set rc [catch {btree_commit $::b1} msg]
79  lappend rc $msg
80} {0 {}}
81do_test btree-1.11 {
82  file size test1.bt
83} {2048}
84do_test btree-1.12 {
85  lindex [btree_pager_stats $::b1] 1
86} {0}
87
88# Reopen the database and attempt to read the record that we wrote.
89#
90do_test btree-2.1 {
91  set rc [catch {btree_cursor $::b1 2 1} ::c1]
92  if {$rc} {lappend rc $::c1}
93  set rc
94} {0}
95do_test btree-2.2 {
96  btree_move_to $::c1 abc
97} {1}
98do_test btree-2.3 {
99  btree_move_to $::c1 xyz
100} {-1}
101do_test btree-2.4 {
102  btree_move_to $::c1 one
103} {0}
104do_test btree-2.5 {
105  btree_key $::c1
106} {one}
107do_test btree-2.6 {
108  btree_data $::c1
109} {1.00}
110do_test btree-2.7 {
111  lindex [btree_pager_stats $::b1] 1
112} {2}
113
114# Do some additional inserts
115#
116do_test btree-3.1 {
117  btree_begin_transaction $::b1
118  btree_insert $::c1 two 2.00
119  btree_key $::c1
120} {two}
121do_test btree-3.1.1 {
122  lindex [btree_pager_stats $::b1] 1
123} {2}
124do_test btree-3.2 {
125  btree_insert $::c1 three 3.00
126  btree_key $::c1
127} {three}
128do_test btree-3.4 {
129  btree_insert $::c1 four 4.00
130  btree_key $::c1
131} {four}
132do_test btree-3.5 {
133  btree_insert $::c1 five 5.00
134  btree_key $::c1
135} {five}
136do_test btree-3.6 {
137  btree_insert $::c1 six 6.00
138  btree_key $::c1
139} {six}
140#btree_page_dump $::b1 2
141do_test btree-3.7 {
142  set rc [btree_move_to $::c1 {}]
143  expr {$rc>0}
144} {1}
145do_test btree-3.8 {
146  btree_key $::c1
147} {five}
148do_test btree-3.9 {
149  btree_data $::c1
150} {5.00}
151do_test btree-3.10 {
152  btree_next $::c1
153  btree_key $::c1
154} {four}
155do_test btree-3.11 {
156  btree_data $::c1
157} {4.00}
158do_test btree-3.12 {
159  btree_next $::c1
160  btree_key $::c1
161} {one}
162do_test btree-3.13 {
163  btree_data $::c1
164} {1.00}
165do_test btree-3.14 {
166  btree_next $::c1
167  btree_key $::c1
168} {six}
169do_test btree-3.15 {
170  btree_data $::c1
171} {6.00}
172do_test btree-3.16 {
173  btree_next $::c1
174  btree_key $::c1
175} {three}
176do_test btree-3.17 {
177  btree_data $::c1
178} {3.00}
179do_test btree-3.18 {
180  btree_next $::c1
181  btree_key $::c1
182} {two}
183do_test btree-3.19 {
184  btree_data $::c1
185} {2.00}
186do_test btree-3.20 {
187  btree_next $::c1
188  btree_key $::c1
189} {}
190do_test btree-3.21 {
191  btree_data $::c1
192} {}
193
194# Commit the changes, reopen and reread the data
195#
196do_test btree-3.22 {
197  set rc [catch {btree_close_cursor $::c1} msg]
198  lappend rc $msg
199} {0 {}}
200do_test btree-3.22.1 {
201  lindex [btree_pager_stats $::b1] 1
202} {1}
203do_test btree-3.23 {
204  set rc [catch {btree_commit $::b1} msg]
205  lappend rc $msg
206} {0 {}}
207do_test btree-3.23.1 {
208  lindex [btree_pager_stats $::b1] 1
209} {0}
210do_test btree-3.24 {
211  file size test1.bt
212} {2048}
213do_test btree-3.25 {
214  set rc [catch {btree_cursor $::b1 2 1} ::c1]
215  if {$rc} {lappend rc $::c1}
216  set rc
217} {0}
218do_test btree-3.25.1 {
219  lindex [btree_pager_stats $::b1] 1
220} {2}
221do_test btree-3.26 {
222  set rc [btree_move_to $::c1 {}]
223  expr {$rc>0}
224} {1}
225do_test btree-3.27 {
226  btree_key $::c1
227} {five}
228do_test btree-3.28 {
229  btree_data $::c1
230} {5.00}
231do_test btree-3.29 {
232  btree_next $::c1
233  btree_key $::c1
234} {four}
235do_test btree-3.30 {
236  btree_data $::c1
237} {4.00}
238do_test btree-3.31 {
239  btree_next $::c1
240  btree_key $::c1
241} {one}
242do_test btree-3.32 {
243  btree_data $::c1
244} {1.00}
245do_test btree-3.33 {
246  btree_next $::c1
247  btree_key $::c1
248} {six}
249do_test btree-3.34 {
250  btree_data $::c1
251} {6.00}
252do_test btree-3.35 {
253  btree_next $::c1
254  btree_key $::c1
255} {three}
256do_test btree-3.36 {
257  btree_data $::c1
258} {3.00}
259do_test btree-3.37 {
260  btree_next $::c1
261  btree_key $::c1
262} {two}
263do_test btree-3.38 {
264  btree_data $::c1
265} {2.00}
266do_test btree-3.39 {
267  btree_next $::c1
268  btree_key $::c1
269} {}
270do_test btree-3.40 {
271  btree_data $::c1
272} {}
273do_test btree-3.41 {
274  lindex [btree_pager_stats $::b1] 1
275} {2}
276
277
278# Now try a delete
279#
280do_test btree-4.1 {
281  btree_begin_transaction $::b1
282  btree_move_to $::c1 one
283  btree_key $::c1
284} {one}
285do_test btree-4.1.1 {
286  lindex [btree_pager_stats $::b1] 1
287} {2}
288do_test btree-4.2 {
289  btree_delete $::c1
290} {}
291do_test btree-4.3 {
292  btree_key $::c1
293} {six}
294do_test btree-4.4 {
295  btree_next $::c1
296  btree_key $::c1
297} {six}
298do_test btree-4.5 {
299  btree_next $::c1
300  btree_key $::c1
301} {three}
302do_test btree-4.4 {
303  btree_move_to $::c1 {}
304  set r {}
305  while 1 {
306    set key [btree_key $::c1]
307    if {$key==""} break
308    lappend r $key
309    lappend r [btree_data $::c1]
310    btree_next $::c1
311  }
312  set r
313} {five 5.00 four 4.00 six 6.00 three 3.00 two 2.00}
314
315# Commit and make sure the delete is still there.
316#
317do_test btree-4.5 {
318  btree_commit $::b1
319  btree_move_to $::c1 {}
320  set r {}
321  while 1 {
322    set key [btree_key $::c1]
323    if {$key==""} break
324    lappend r $key
325    lappend r [btree_data $::c1]
326    btree_next $::c1
327  }
328  set r
329} {five 5.00 four 4.00 six 6.00 three 3.00 two 2.00}
330
331# Completely close the database and reopen it.  Then check
332# the data again.
333#
334do_test btree-4.6 {
335  lindex [btree_pager_stats $::b1] 1
336} {2}
337do_test btree-4.7 {
338  btree_close_cursor $::c1
339  lindex [btree_pager_stats $::b1] 1
340} {0}
341do_test btree-4.8 {
342  btree_close $::b1
343  set ::b1 [btree_open test1.bt]
344  set ::c1 [btree_cursor $::b1 2 1]
345  lindex [btree_pager_stats $::b1] 1
346} {2}
347do_test btree-4.9 {
348  set r {}
349  btree_first $::c1
350  while 1 {
351    set key [btree_key $::c1]
352    if {$key==""} break
353    lappend r $key
354    lappend r [btree_data $::c1]
355    btree_next $::c1
356  }
357  set r
358} {five 5.00 four 4.00 six 6.00 three 3.00 two 2.00}
359
360# Try to read and write meta data
361#
362do_test btree-5.1 {
363  btree_get_meta $::b1
364} {0 0 0 0 0 0 0 0 0 0}
365do_test btree-5.2 {
366  set rc [catch {btree_update_meta $::b1 1 2 3 4 5 6 7 8 9 10} msg]
367  lappend rc $msg
368} {1 SQLITE_ERROR}
369do_test btree-5.3 {
370  btree_begin_transaction $::b1
371  set rc [catch {btree_update_meta $::b1 1 2 3 4 5 6 7 8 9 10} msg]
372  lappend rc $msg
373} {0 {}}
374do_test btree-5.4 {
375  btree_get_meta $::b1
376} {0 2 3 4 5 6 7 8 9 10}
377do_test btree-5.5 {
378  btree_close_cursor $::c1
379  btree_rollback $::b1
380  btree_get_meta $::b1
381} {0 0 0 0 0 0 0 0 0 0}
382do_test btree-5.6 {
383  btree_begin_transaction $::b1
384  btree_update_meta $::b1 999 10 20 30 40 50 60 70 80 90
385  btree_commit $::b1
386  btree_get_meta $::b1
387} {0 10 20 30 40 50 60 70 80 90}
388
389proc select_all {cursor} {
390  set r {}
391  btree_move_to $cursor {}
392  while 1 {
393    set key [btree_key $cursor]
394    if {$key==""} break
395    lappend r $key
396    lappend r [btree_data $cursor]
397    btree_next $cursor
398  }
399  return $r
400}
401proc select_keys {cursor} {
402  set r {}
403  btree_move_to $cursor {}
404  while 1 {
405    set key [btree_key $cursor]
406    if {$key==""} break
407    lappend r $key
408    btree_next $cursor
409  }
410  return $r
411}
412
413# Try to create a new table in the database file
414#
415do_test btree-6.1 {
416  set rc [catch {btree_create_table $::b1} msg]
417  lappend rc $msg
418} {1 SQLITE_ERROR}
419do_test btree-6.2 {
420  btree_begin_transaction $::b1
421  set ::t2 [btree_create_table $::b1]
422} {3}
423do_test btree-6.2.1 {
424  lindex [btree_pager_stats $::b1] 1
425} {1}
426do_test btree-6.2.2 {
427  set ::c2 [btree_cursor $::b1 $::t2 1]
428  lindex [btree_pager_stats $::b1] 1
429} {2}
430do_test btree-6.2.3 {
431  btree_insert $::c2 ten 10
432  btree_key $::c2
433} {ten}
434do_test btree-6.3 {
435  btree_commit $::b1
436  set ::c1 [btree_cursor $::b1 2 1]
437  lindex [btree_pager_stats $::b1] 1
438} {3}
439do_test btree-6.3.1 {
440  select_all $::c1
441} {five 5.00 four 4.00 six 6.00 three 3.00 two 2.00}
442#btree_page_dump $::b1 3
443do_test btree-6.4 {
444  select_all $::c2
445} {ten 10}
446
447# Drop the new table, then create it again anew.
448#
449do_test btree-6.5 {
450  btree_begin_transaction $::b1
451} {}
452do_test btree-6.6 {
453  btree_close_cursor $::c2
454} {}
455do_test btree-6.6.1 {
456  lindex [btree_pager_stats $::b1] 1
457} {2}
458do_test btree-6.7 {
459  btree_drop_table $::b1 $::t2
460} {}
461do_test btree-6.7.1 {
462  lindex [btree_get_meta $::b1] 0
463} {1}
464do_test btree-6.8 {
465  set ::t2 [btree_create_table $::b1]
466} {3}
467do_test btree-6.8.1 {
468  lindex [btree_get_meta $::b1] 0
469} {0}
470do_test btree-6.9 {
471  set ::c2 [btree_cursor $::b1 $::t2 1]
472  lindex [btree_pager_stats $::b1] 1
473} {3}
474
475do_test btree-6.9.1 {
476  btree_move_to $::c2 {}
477  btree_key $::c2
478} {}
479
480# If we drop table 2 it just clears the table.  Table 2 always exists.
481#
482do_test btree-6.10 {
483  btree_close_cursor $::c1
484  btree_drop_table $::b1 2
485  set ::c1 [btree_cursor $::b1 2 1]
486  btree_move_to $::c1 {}
487  btree_key $::c1
488} {}
489do_test btree-6.11 {
490  btree_commit $::b1
491  select_all $::c1
492} {}
493do_test btree-6.12 {
494  select_all $::c2
495} {}
496do_test btree-6.13 {
497  btree_close_cursor $::c2
498  lindex [btree_pager_stats $::b1] 1
499} {2}
500
501# Check to see that pages defragment properly.  To do this test we will
502#
503#   1.  Fill the first page table 2 with data.
504#   2.  Delete every other entry of table 2.
505#   3.  Insert a single entry that requires more contiguous
506#       space than is available.
507#
508do_test btree-7.1 {
509  btree_begin_transaction $::b1
510} {}
511catch {unset key}
512catch {unset data}
513do_test btree-7.2 {
514  for {set i 0} {$i<36} {incr i} {
515    set key [format %03d $i]
516    set data "*** $key ***"
517    btree_insert $::c1 $key $data
518  }
519  lrange [btree_cursor_dump $::c1] 4 5
520} {8 1}
521do_test btree-7.3 {
522  btree_move_to $::c1 000
523  while {[btree_key $::c1]!=""} {
524    btree_delete $::c1
525    btree_next $::c1
526    btree_next $::c1
527  }
528  lrange [btree_cursor_dump $::c1] 4 5
529} {512 19}
530#btree_page_dump $::b1 2
531do_test btree-7.4 {
532  btree_insert $::c1 018 {*** 018 ***+++}
533  btree_key $::c1
534} {018}
535do_test btree-7.5 {
536  lrange [btree_cursor_dump $::c1] 4 5
537} {480 1}
538#btree_page_dump $::b1 2
539
540# Delete an entry to make a hole of a known size, then immediately recreate
541# that entry.  This tests the path into allocateSpace where the hole exactly
542# matches the size of the desired space.
543#
544do_test btree-7.6 {
545  btree_move_to $::c1 007
546  btree_delete $::c1
547  btree_move_to $::c1 011
548  btree_delete $::c1
549} {}
550do_test btree-7.7 {
551  lindex [btree_cursor_dump $::c1] 5
552} {3}
553#btree_page_dump $::b1 2
554do_test btree-7.8 {
555  btree_insert $::c1 007 {*** 007 ***}
556  lindex [btree_cursor_dump $::c1] 5
557} {2}
558#btree_page_dump $::b1 2
559
560# Make sure the freeSpace() routine properly coaleses adjacent memory blocks
561#
562do_test btree-7.9 {
563  btree_move_to $::c1 013
564  btree_delete $::c1
565  lrange [btree_cursor_dump $::c1] 4 5
566} {536 2}
567do_test btree-7.10 {
568  btree_move_to $::c1 009
569  btree_delete $::c1
570  lrange [btree_cursor_dump $::c1] 4 5
571} {564 2}
572do_test btree-7.11 {
573  btree_move_to $::c1 018
574  btree_delete $::c1
575  lrange [btree_cursor_dump $::c1] 4 5
576} {596 2}
577do_test btree-7.13 {
578  btree_move_to $::c1 033
579  btree_delete $::c1
580  lrange [btree_cursor_dump $::c1] 4 5
581} {624 3}
582do_test btree-7.14 {
583  btree_move_to $::c1 035
584  btree_delete $::c1
585  lrange [btree_cursor_dump $::c1] 4 5
586} {652 2}
587#btree_page_dump $::b1 2
588do_test btree-7.15 {
589  lindex [btree_pager_stats $::b1] 1
590} {2}
591
592# Check to see that data on overflow pages work correctly.
593#
594do_test btree-8.1 {
595  set data "*** This is a very long key "
596  while {[string length $data]<256} {append data $data}
597  set ::data $data
598  btree_insert $::c1 020 $data
599} {}
600#btree_page_dump $::b1 2
601do_test btree-8.1.1 {
602  lindex [btree_pager_stats $::b1] 1
603} {2}
604#btree_pager_ref_dump $::b1
605do_test btree-8.2 {
606  string length [btree_data $::c1]
607} [string length $::data]
608do_test btree-8.3 {
609  btree_data $::c1
610} $::data
611do_test btree-8.4 {
612  btree_delete $::c1
613} {}
614do_test btree-8.4.1 {
615  lindex [btree_get_meta $::b1] 0
616} [expr {int(([string length $::data]-238+1019)/1020)}]
617do_test btree-8.5 {
618  set data "*** This is an even longer key"
619  while {[string length $data]<2000} {append data $data}
620  set ::data $data
621  btree_insert $::c1 020 $data
622} {}
623do_test btree-8.6 {
624  string length [btree_data $::c1]
625} [string length $::data]
626do_test btree-8.7 {
627  btree_data $::c1
628} $::data
629do_test btree-8.8 {
630  btree_commit $::b1
631  btree_data $::c1
632} $::data
633do_test btree-8.9 {
634  btree_close_cursor $::c1
635  btree_close $::b1
636  set ::b1 [btree_open test1.bt]
637  set ::c1 [btree_cursor $::b1 2 1]
638  btree_move_to $::c1 020
639  btree_data $::c1
640} $::data
641do_test btree-8.10 {
642  btree_begin_transaction $::b1
643  btree_delete $::c1
644} {}
645do_test btree-8.11 {
646  lindex [btree_get_meta $::b1] 0
647} [expr {int(([string length $::data]-238+1019)/1020)}]
648
649# Now check out keys on overflow pages.
650#
651do_test btree-8.12 {
652  set ::keyprefix "This is a long prefix to a key "
653  while {[string length $::keyprefix]<256} {append ::keyprefix $::keyprefix}
654  btree_close_cursor $::c1
655  btree_drop_table $::b1 2
656  lindex [btree_get_meta $::b1] 0
657} {4}
658do_test btree-8.12.1 {
659  set ::c1 [btree_cursor $::b1 2 1]
660  btree_insert $::c1 ${::keyprefix}1 1
661  btree_data $::c1
662} {1}
663do_test btree-8.13 {
664  btree_key $::c1
665} ${keyprefix}1
666do_test btree-8.14 {
667  btree_insert $::c1 ${::keyprefix}2 2
668  btree_insert $::c1 ${::keyprefix}3 3
669  btree_key $::c1
670} ${keyprefix}3
671do_test btree-8.15 {
672  btree_move_to $::c1 ${::keyprefix}2
673  btree_data $::c1
674} {2}
675do_test btree-8.16 {
676  btree_move_to $::c1 ${::keyprefix}1
677  btree_data $::c1
678} {1}
679do_test btree-8.17 {
680  btree_move_to $::c1 ${::keyprefix}3
681  btree_data $::c1
682} {3}
683do_test btree-8.18 {
684  lindex [btree_get_meta $::b1] 0
685} {1}
686do_test btree-8.19 {
687  btree_move_to $::c1 ${::keyprefix}2
688  btree_key $::c1
689} ${::keyprefix}2
690#btree_page_dump $::b1 2
691do_test btree-8.20 {
692  btree_delete $::c1
693  btree_next $::c1
694  btree_key $::c1
695} ${::keyprefix}3
696#btree_page_dump $::b1 2
697do_test btree-8.21 {
698  lindex [btree_get_meta $::b1] 0
699} {2}
700do_test btree-8.22 {
701  lindex [btree_pager_stats $::b1] 1
702} {2}
703do_test btree-8.23 {
704  btree_close_cursor $::c1
705  btree_drop_table $::b1 2
706  set ::c1 [btree_cursor $::b1 2 1]
707  lindex [btree_get_meta $::b1] 0
708} {4}
709do_test btree-8.24 {
710  lindex [btree_pager_stats $::b1] 1
711} {2}
712#btree_pager_ref_dump $::b1
713
714# Check page splitting logic
715#
716do_test btree-9.1 {
717  for {set i 1} {$i<=19} {incr i} {
718    set key [format %03d $i]
719    set data "*** $key *** $key *** $key *** $key ***"
720    btree_insert $::c1 $key $data
721  }
722} {}
723#btree_tree_dump $::b1 2
724#btree_pager_ref_dump $::b1
725#set pager_refinfo_enable 1
726do_test btree-9.2 {
727  btree_insert $::c1 020 {*** 020 *** 020 *** 020 *** 020 ***}
728  select_keys $::c1
729} {001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020}
730#btree_page_dump $::b1 5
731#btree_page_dump $::b1 2
732#btree_page_dump $::b1 7
733#btree_pager_ref_dump $::b1
734#set pager_refinfo_enable 0
735
736# The previous "select_keys" command left the cursor pointing at the root
737# page.  So there should only be two pages checked out.  2 (the root) and
738# page 1.
739do_test btree-9.2.1 {
740  lindex [btree_pager_stats $::b1] 1
741} {2}
742for {set i 1} {$i<=20} {incr i} {
743  do_test btree-9.3.$i.1 [subst {
744    btree_move_to $::c1 [format %03d $i]
745    btree_key $::c1
746  }] [format %03d $i]
747  do_test btree-9.3.$i.2 [subst {
748    btree_move_to $::c1 [format %03d $i]
749    string range \[btree_data $::c1\] 0 10
750  }] "*** [format %03d $i] ***"
751}
752do_test btree-9.4.1 {
753  lindex [btree_pager_stats $::b1] 1
754} {3}
755
756# Check the page joining logic.
757#
758#btree_page_dump $::b1 2
759#btree_pager_ref_dump $::b1
760do_test btree-9.4.2 {
761  btree_move_to $::c1 005
762  btree_delete $::c1
763} {}
764#btree_page_dump $::b1 2
765for {set i 1} {$i<=19} {incr i} {
766  if {$i==5} continue
767  do_test btree-9.5.$i.1 [subst {
768    btree_move_to $::c1 [format %03d $i]
769    btree_key $::c1
770  }] [format %03d $i]
771  do_test btree-9.5.$i.2 [subst {
772    btree_move_to $::c1 [format %03d $i]
773    string range \[btree_data $::c1\] 0 10
774  }] "*** [format %03d $i] ***"
775}
776#btree_pager_ref_dump $::b1
777do_test btree-9.6 {
778  btree_close_cursor $::c1
779  lindex [btree_pager_stats $::b1] 1
780} {1}
781do_test btree-9.7 {
782  btree_rollback $::b1
783  lindex [btree_pager_stats $::b1] 1
784} {0}
785
786# Create a tree of depth two.  That is, there is a single divider entry
787# on the root pages and two leaf pages.  Then delete the divider entry
788# see what happens.
789#
790do_test btree-10.1 {
791  btree_begin_transaction $::b1
792  btree_drop_table $::b1 2
793  lindex [btree_pager_stats $::b1] 1
794} {1}
795do_test btree-10.2 {
796  set ::c1 [btree_cursor $::b1 2 1]
797  lindex [btree_pager_stats $::b1] 1
798} {2}
799do_test btree-10.3 {
800  for {set i 1} {$i<=20} {incr i} {
801    set key [format %03d $i]
802    set data "*** $key *** $key *** $key *** $key ***"
803    btree_insert $::c1 $key $data
804  }
805  select_keys $::c1
806} {001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020}
807#btree_page_dump $::b1 7
808#btree_page_dump $::b1 2
809#btree_page_dump $::b1 6
810do_test btree-10.4 {
811  btree_move_to $::c1 011
812  btree_delete $::c1
813  select_keys $::c1
814} {001 002 003 004 005 006 007 008 009 010 012 013 014 015 016 017 018 019 020}
815#btree_tree_dump $::b1 2
816#btree_pager_ref_dump $::b1
817for {set i 1} {$i<=20} {incr i} {
818  do_test btree-10.5.$i {
819    btree_move_to $::c1 [format %03d $i]
820    lindex [btree_pager_stats $::b1] 1
821  } {2}
822  #btree_pager_ref_dump $::b1
823  #btree_tree_dump $::b1 2
824}
825
826# Create a tree with lots more pages
827#
828catch {unset ::data}
829catch {unset ::key}
830for {set i 21} {$i<=1000} {incr i} {
831  do_test btree-11.1.$i.1 {
832    set key [format %03d $i]
833    set ::data "*** $key *** $key *** $key *** $key ***"
834    btree_insert $::c1 $key $data
835    btree_key $::c1
836  } [format %03d $i]
837  do_test btree-11.1.$i.2 {
838    btree_data $::c1
839  } $::data
840  set ::key [format %03d [expr {$i/2}]]
841  if {$::key=="011"} {set ::key 010}
842  do_test btree-11.1.$i.3 {
843    btree_move_to $::c1 $::key
844    btree_key $::c1
845  } $::key
846}
847catch {unset ::data}
848catch {unset ::key}
849
850# Make sure our reference count is still correct.
851#
852do_test btree-11.2 {
853  btree_close_cursor $::c1
854  lindex [btree_pager_stats $::b1] 1
855} {1}
856do_test btree-11.3 {
857  set ::c1 [btree_cursor $::b1 2 1]
858  lindex [btree_pager_stats $::b1] 1
859} {2}
860#btree_page_dump $::b1 2
861
862# Delete the dividers on the root page
863#
864do_test btree-11.4 {
865  btree_move_to $::c1 257
866  btree_delete $::c1
867  btree_next $::c1
868  btree_key $::c1
869} {258}
870do_test btree-11.4.1 {
871  btree_move_to $::c1 256
872  btree_key $::c1
873} {256}
874do_test btree-11.4.2 {
875  btree_move_to $::c1 258
876  btree_key $::c1
877} {258}
878do_test btree-11.4.3 {
879  btree_move_to $::c1 259
880  btree_key $::c1
881} {259}
882do_test btree-11.4.4 {
883  btree_move_to $::c1 257
884  set n [btree_key $::c1]
885  expr {$n==256||$n==258}
886} {1}
887do_test btree-11.5 {
888  btree_move_to $::c1 513
889  btree_delete $::c1
890  btree_next $::c1
891  btree_key $::c1
892} {514}
893do_test btree-11.5.1 {
894  btree_move_to $::c1 512
895  btree_key $::c1
896} {512}
897do_test btree-11.5.2 {
898  btree_move_to $::c1 514
899  btree_key $::c1
900} {514}
901do_test btree-11.5.3 {
902  btree_move_to $::c1 515
903  btree_key $::c1
904} {515}
905do_test btree-11.5.4 {
906  btree_move_to $::c1 513
907  set n [btree_key $::c1]
908  expr {$n==512||$n==514}
909} {1}
910do_test btree-11.6 {
911  btree_move_to $::c1 769
912  btree_delete $::c1
913  btree_next $::c1
914  btree_key $::c1
915} {770}
916do_test btree-11.6.1 {
917  btree_move_to $::c1 768
918  btree_key $::c1
919} {768}
920do_test btree-11.6.2 {
921  btree_move_to $::c1 771
922  btree_key $::c1
923} {771}
924do_test btree-11.6.3 {
925  btree_move_to $::c1 770
926  btree_key $::c1
927} {770}
928do_test btree-11.6.4 {
929  btree_move_to $::c1 769
930  set n [btree_key $::c1]
931  expr {$n==768||$n==770}
932} {1}
933#btree_page_dump $::b1 2
934#btree_page_dump $::b1 25
935
936# Change the data on an intermediate node such that the node becomes overfull
937# and has to split.  We happen to know that intermediate nodes exist on
938# 337, 401 and 465 by the btree_page_dumps above
939#
940catch {unset ::data}
941set ::data {This is going to be a very long data segment}
942append ::data $::data
943append ::data $::data
944do_test btree-12.1 {
945  btree_insert $::c1 337 $::data
946  btree_data $::c1
947} $::data
948do_test btree-12.2 {
949  btree_insert $::c1 401 $::data
950  btree_data $::c1
951} $::data
952do_test btree-12.3 {
953  btree_insert $::c1 465 $::data
954  btree_data $::c1
955} $::data
956do_test btree-12.4 {
957  btree_move_to $::c1 337
958  btree_key $::c1
959} {337}
960do_test btree-12.5 {
961  btree_data $::c1
962} $::data
963do_test btree-12.6 {
964  btree_next $::c1
965  btree_key $::c1
966} {338}
967do_test btree-12.7 {
968  btree_move_to $::c1 464
969  btree_key $::c1
970} {464}
971do_test btree-12.8 {
972  btree_next $::c1
973  btree_data $::c1
974} $::data
975do_test btree-12.9 {
976  btree_next $::c1
977  btree_key $::c1
978} {466}
979do_test btree-12.10 {
980  btree_move_to $::c1 400
981  btree_key $::c1
982} {400}
983do_test btree-12.11 {
984  btree_next $::c1
985  btree_data $::c1
986} $::data
987do_test btree-12.12 {
988  btree_next $::c1
989  btree_key $::c1
990} {402}
991do_test btree-13.1 {
992  btree_integrity_check $::b1 2 3
993} {}
994
995# To Do:
996#
997#   1.  Do some deletes from the 3-layer tree
998#   2.  Commit and reopen the database
999#   3.  Read every 15th entry and make sure it works
1000#   4.  Implement btree_sanity and put it throughout this script
1001#
1002
1003do_test btree-15.98 {
1004  btree_close_cursor $::c1
1005  lindex [btree_pager_stats $::b1] 1
1006} {1}
1007do_test btree-15.99 {
1008  btree_rollback $::b1
1009  lindex [btree_pager_stats $::b1] 1
1010} {0}
1011btree_pager_ref_dump $::b1
1012
1013do_test btree-99.1 {
1014  btree_close $::b1
1015} {}
1016catch {unset data}
1017catch {unset key}
1018
1019} ;# end if( not mem: and has pager_open command );
1020
1021finish_test
1022