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