1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 1999,2008 Oracle.  All rights reserved.
4#
5# $Id: test074.tcl,v 12.6 2008/01/08 20:58:53 bostic Exp $
6#
7# TEST	test074
8# TEST	Test of DB_NEXT_NODUP.
9proc test074 { method {dir -nextnodup} {nitems 100} {tnum "074"} args } {
10	source ./include.tcl
11	global alphabet
12	global is_je_test
13	global rand_init
14
15	set omethod [convert_method $method]
16	set args [convert_args $method $args]
17
18	berkdb srand $rand_init
19
20	# Data prefix--big enough that we get a mix of on-page, off-page,
21	# and multi-off-page dups with the default nitems
22	if { [is_fixed_length $method] == 1 } {
23		set globaldata "somedata"
24	} else {
25		set globaldata [repeat $alphabet 4]
26	}
27
28	puts "Test$tnum $omethod ($args): Test of $dir"
29
30	# First, test non-dup (and not-very-interesting) case with
31	# all db types.
32
33	puts "\tTest$tnum.a: No duplicates."
34
35	set txnenv 0
36	set eindex [lsearch -exact $args "-env"]
37	#
38	# If we are using an env, then testfile should just be the db name.
39	# Otherwise it is the test directory and the name.
40	if { $eindex == -1 } {
41		set testfile $testdir/test$tnum-nodup.db
42		set env NULL
43	} else {
44		set testfile test$tnum-nodup.db
45		incr eindex
46		set env [lindex $args $eindex]
47		set txnenv [is_txnenv $env]
48		if { $txnenv == 1 } {
49			append args " -auto_commit "
50		}
51		set testdir [get_home $env]
52	}
53	cleanup $testdir $env
54	set db [eval {berkdb_open -create -mode 0644} $omethod\
55	    $args {$testfile}]
56	error_check_good db_open [is_valid_db $db] TRUE
57	set txn ""
58
59	# Insert nitems items.
60	puts "\t\tTest$tnum.a.1: Put loop."
61	for {set i 1} {$i <= $nitems} {incr i} {
62		#
63		# If record based, set key to $i * 2 to leave
64		# holes/unused entries for further testing.
65		#
66		if {[is_record_based $method] == 1} {
67			set key [expr $i * 2]
68		} else {
69			set key "key$i"
70		}
71		set data "$globaldata$i"
72		if { $txnenv == 1 } {
73			set t [$env txn]
74			error_check_good txn [is_valid_txn $t $env] TRUE
75			set txn "-txn $t"
76		}
77		set ret [eval {$db put} $txn {$key \
78		    [chop_data $method $data]}]
79		error_check_good put($i) $ret 0
80		if { $txnenv == 1 } {
81			error_check_good txn [$t commit] 0
82		}
83	}
84
85	puts "\t\tTest$tnum.a.2: Get($dir)"
86
87	# foundarray($i) is set when key number i is found in the database
88	if { $txnenv == 1 } {
89		set t [$env txn]
90		error_check_good txn [is_valid_txn $t $env] TRUE
91		set txn "-txn $t"
92	}
93	set dbc [eval {$db cursor} $txn]
94	error_check_good db_cursor [is_valid_cursor $dbc $db] TRUE
95
96	# Initialize foundarray($i) to zero for all $i
97	for {set i 1} {$i < $nitems} {incr i} {
98		set foundarray($i) 0
99	}
100
101	# Walk database using $dir and record each key gotten.
102	for {set i 1} {$i <= $nitems} {incr i} {
103		set dbt [$dbc get $dir]
104		set key [lindex [lindex $dbt 0] 0]
105		if {[is_record_based $method] == 1} {
106			set num [expr $key / 2]
107			set desired_key $key
108			error_check_good $method:num $key [expr $num * 2]
109		} else {
110			set num [string range $key 3 end]
111			set desired_key key$num
112		}
113
114		error_check_good dbt_correct($i) $dbt\
115		    [list [list $desired_key\
116		    [pad_data $method $globaldata$num]]]
117
118		set foundarray($num) 1
119	}
120
121	puts "\t\tTest$tnum.a.3: Final key."
122	error_check_good last_db_get [$dbc get $dir] [list]
123
124	puts "\t\tTest$tnum.a.4: Verify loop."
125	for { set i 1 } { $i <= $nitems } { incr i } {
126		error_check_good found_key($i) $foundarray($i) 1
127	}
128
129	error_check_good dbc_close(nodup) [$dbc close] 0
130	if { $txnenv == 1 } {
131		error_check_good txn [$t commit] 0
132	}
133
134	# If we are a method that doesn't allow dups, verify that
135	# we get an empty list if we try to use DB_NEXT_DUP
136	if { [is_record_based $method] == 1 || [is_rbtree $method] == 1 } {
137		if { $txnenv == 1 } {
138			set t [$env txn]
139			error_check_good txn [is_valid_txn $t $env] TRUE
140			set txn "-txn $t"
141		}
142		puts "\t\tTest$tnum.a.5: Check DB_NEXT_DUP for $method."
143		set dbc [eval {$db cursor} $txn]
144		error_check_good db_cursor [is_valid_cursor $dbc $db] TRUE
145
146		set dbt [$dbc get $dir]
147		error_check_good $method:nextdup [$dbc get -nextdup] [list]
148		error_check_good dbc_close(nextdup) [$dbc close] 0
149		if { $txnenv == 1 } {
150			error_check_good txn [$t commit] 0
151		}
152	}
153	error_check_good db_close(nodup) [$db close] 0
154
155	# Quit here if we're a method that won't allow dups.
156	if { [is_record_based $method] == 1 || [is_rbtree $method] == 1 } {
157		puts "\tTest$tnum: Skipping remainder for method $method."
158		return
159	}
160
161	foreach opt { "-dup" "-dupsort" } {
162		if { $is_je_test && $opt == "-dup" } {
163			continue
164		}
165
166		#
167		# If we are using an env, then testfile should just be the
168		# db name.  Otherwise it is the test directory and the name.
169		if { $eindex == -1 } {
170			set testfile $testdir/test$tnum$opt.db
171		} else {
172			set testfile test$tnum$opt.db
173		}
174
175		if { [string compare $opt "-dupsort"] == 0 } {
176			set opt "-dup -dupsort"
177		}
178
179		puts "\tTest$tnum.b: Duplicates ($opt)."
180
181		puts "\t\tTest$tnum.b.1 ($opt): Put loop."
182		set db [eval {berkdb_open -create -mode 0644}\
183		    $opt $omethod $args {$testfile}]
184		error_check_good db_open [is_valid_db $db] TRUE
185
186		# Insert nitems different keys such that key i has i dups.
187		for {set i 1} {$i <= $nitems} {incr i} {
188			set key key$i
189
190			for {set j 1} {$j <= $i} {incr j} {
191				if { $j < 10 } {
192					set data "${globaldata}00$j"
193				} elseif { $j < 100 } {
194					set data "${globaldata}0$j"
195				} else {
196					set data "$globaldata$j"
197				}
198
199				if { $txnenv == 1 } {
200					set t [$env txn]
201					error_check_good txn \
202					    [is_valid_txn $t $env] TRUE
203					set txn "-txn $t"
204				}
205				set ret [eval {$db put} $txn {$key $data}]
206				error_check_good put($i,$j) $ret 0
207				if { $txnenv == 1 } {
208					error_check_good txn [$t commit] 0
209				}
210			}
211		}
212
213		# Initialize foundarray($i) to 0 for all i.
214		unset foundarray
215		for { set i 1 } { $i <= $nitems } { incr i } {
216			set foundarray($i) 0
217		}
218
219		# Get loop--after each get, move forward a random increment
220		# within the duplicate set.
221		puts "\t\tTest$tnum.b.2 ($opt): Get loop."
222		set one "001"
223		if { $txnenv == 1 } {
224			set t [$env txn]
225			error_check_good txn [is_valid_txn $t $env] TRUE
226			set txn "-txn $t"
227		}
228		set dbc [eval {$db cursor} $txn]
229		error_check_good dbc($opt) [is_valid_cursor $dbc $db] TRUE
230		for { set i 1 } { $i <= $nitems } { incr i } {
231			set dbt [$dbc get $dir]
232			set key [lindex [lindex $dbt 0] 0]
233			set num [string range $key 3 end]
234
235			set desired_key key$num
236			if { [string compare $dir "-prevnodup"] == 0 } {
237				if { $num < 10 } {
238					set one "00$num"
239				} elseif { $num < 100 } {
240					set one "0$num"
241				} else {
242					set one $num
243				}
244			}
245
246			error_check_good dbt_correct($i) $dbt\
247				[list [list $desired_key\
248				    "$globaldata$one"]]
249
250			set foundarray($num) 1
251
252			# Go forward by some number w/i dup set.
253			set inc [berkdb random_int 0 [expr $num - 1]]
254			for { set j 0 } { $j < $inc } { incr j } {
255				eval {$dbc get -nextdup}
256			}
257		}
258
259		puts "\t\tTest$tnum.b.3 ($opt): Final key."
260		error_check_good last_db_get($opt) [$dbc get $dir] [list]
261
262		# Verify
263		puts "\t\tTest$tnum.b.4 ($opt): Verify loop."
264		for { set i 1 } { $i <= $nitems } { incr i } {
265			error_check_good found_key($i) $foundarray($i) 1
266		}
267
268		error_check_good dbc_close [$dbc close] 0
269		if { $txnenv == 1 } {
270			error_check_good txn [$t commit] 0
271		}
272		error_check_good db_close [$db close] 0
273	}
274}
275