1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 1999-2009 Oracle.  All rights reserved.
4#
5# $Id$
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 || [is_compressed $args] } {
163			if { $opt == "-dup" } {
164				continue
165			}
166		}
167
168		#
169		# If we are using an env, then testfile should just be the
170		# db name.  Otherwise it is the test directory and the name.
171		if { $eindex == -1 } {
172			set testfile $testdir/test$tnum$opt.db
173		} else {
174			set testfile test$tnum$opt.db
175		}
176
177		if { [string compare $opt "-dupsort"] == 0 } {
178			set opt "-dup -dupsort"
179		}
180
181		puts "\tTest$tnum.b: Duplicates ($opt)."
182
183		puts "\t\tTest$tnum.b.1 ($opt): Put loop."
184		set db [eval {berkdb_open -create -mode 0644}\
185		    $opt $omethod $args {$testfile}]
186		error_check_good db_open [is_valid_db $db] TRUE
187
188		# Insert nitems different keys such that key i has i dups.
189		for {set i 1} {$i <= $nitems} {incr i} {
190			set key key$i
191
192			for {set j 1} {$j <= $i} {incr j} {
193				if { $j < 10 } {
194					set data "${globaldata}00$j"
195				} elseif { $j < 100 } {
196					set data "${globaldata}0$j"
197				} else {
198					set data "$globaldata$j"
199				}
200
201				if { $txnenv == 1 } {
202					set t [$env txn]
203					error_check_good txn \
204					    [is_valid_txn $t $env] TRUE
205					set txn "-txn $t"
206				}
207				set ret [eval {$db put} $txn {$key $data}]
208				error_check_good put($i,$j) $ret 0
209				if { $txnenv == 1 } {
210					error_check_good txn [$t commit] 0
211				}
212			}
213		}
214
215		# Initialize foundarray($i) to 0 for all i.
216		unset foundarray
217		for { set i 1 } { $i <= $nitems } { incr i } {
218			set foundarray($i) 0
219		}
220
221		# Get loop--after each get, move forward a random increment
222		# within the duplicate set.
223		puts "\t\tTest$tnum.b.2 ($opt): Get loop."
224		set one "001"
225		if { $txnenv == 1 } {
226			set t [$env txn]
227			error_check_good txn [is_valid_txn $t $env] TRUE
228			set txn "-txn $t"
229		}
230		set dbc [eval {$db cursor} $txn]
231		error_check_good dbc($opt) [is_valid_cursor $dbc $db] TRUE
232		for { set i 1 } { $i <= $nitems } { incr i } {
233			set dbt [$dbc get $dir]
234			set key [lindex [lindex $dbt 0] 0]
235			set num [string range $key 3 end]
236
237			set desired_key key$num
238			if { [string compare $dir "-prevnodup"] == 0 } {
239				if { $num < 10 } {
240					set one "00$num"
241				} elseif { $num < 100 } {
242					set one "0$num"
243				} else {
244					set one $num
245				}
246			}
247
248			error_check_good dbt_correct($i) $dbt\
249				[list [list $desired_key\
250				    "$globaldata$one"]]
251
252			set foundarray($num) 1
253
254			# Go forward by some number w/i dup set.
255			set inc [berkdb random_int 0 [expr $num - 1]]
256			for { set j 0 } { $j < $inc } { incr j } {
257				eval {$dbc get -nextdup}
258			}
259		}
260
261		puts "\t\tTest$tnum.b.3 ($opt): Final key."
262		error_check_good last_db_get($opt) [$dbc get $dir] [list]
263
264		# Verify
265		puts "\t\tTest$tnum.b.4 ($opt): Verify loop."
266		for { set i 1 } { $i <= $nitems } { incr i } {
267			error_check_good found_key($i) $foundarray($i) 1
268		}
269
270		error_check_good dbc_close [$dbc close] 0
271		if { $txnenv == 1 } {
272			error_check_good txn [$t commit] 0
273		}
274		error_check_good db_close [$db close] 0
275	}
276}
277