1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 1996-2009 Oracle.  All rights reserved.
4#
5# $Id$
6#
7# TEST	test057
8# TEST	Cursor maintenance during key deletes.
9# TEST	1.  Delete a key with a cursor.  Add the key back with a regular
10# TEST	put.  Make sure the cursor can't get the new item.
11# TEST	2.  Put two cursors on one item.  Delete through one cursor,
12# TEST	check that the other sees the change.
13# TEST	3.  Same as 2, with the two cursors on a duplicate.
14
15proc test057 { method args } {
16	global errorInfo
17	source ./include.tcl
18
19	set args [convert_args $method $args]
20	set omethod [convert_method $method]
21
22	append args " -create -mode 0644 -dup "
23	if { [is_record_based $method] == 1 || [is_rbtree $method] == 1 } {
24		puts "Test057: skipping for method $method"
25		return
26	}
27
28	# Btree with compression does not support unsorted duplicates.
29	if { [is_compressed $args] == 1 } {
30		puts "Test057 skipping for btree with compression."
31		return
32	}
33
34	puts "Test057: $method delete and replace in presence of cursor."
35
36	# Create the database and open the dictionary
37	set txnenv 0
38	set eindex [lsearch -exact $args "-env"]
39	#
40	# If we are using an env, then testfile should just be the db name.
41	# Otherwise it is the test directory and the name.
42	if { $eindex == -1 } {
43		set testfile $testdir/test057.db
44		set env NULL
45	} else {
46		set testfile test057.db
47		incr eindex
48		set env [lindex $args $eindex]
49		set txnenv [is_txnenv $env]
50		if { $txnenv == 1 } {
51			append args " -auto_commit "
52		}
53		set testdir [get_home $env]
54	}
55	cleanup $testdir $env
56
57	set flags ""
58	set txn ""
59
60	set db [eval {berkdb_open} $args {$omethod $testfile}]
61	error_check_good dbopen:dup [is_valid_db $db] TRUE
62
63	puts "\tTest057.a: Set cursor, delete cursor, put with key."
64	# Put three keys in the database
65	for { set key 1 } { $key <= 3 } {incr key} {
66		if { $txnenv == 1 } {
67			set t [$env txn]
68			error_check_good txn [is_valid_txn $t $env] TRUE
69			set txn "-txn $t"
70		}
71		set r [eval {$db put} $txn $flags {$key datum$key}]
72		error_check_good put $r 0
73		if { $txnenv == 1 } {
74			error_check_good txn [$t commit] 0
75		}
76	}
77
78	# Retrieve keys sequentially so we can figure out their order
79	set i 1
80	if { $txnenv == 1 } {
81		set t [$env txn]
82		error_check_good txn [is_valid_txn $t $env] TRUE
83		set txn "-txn $t"
84	}
85	set curs [eval {$db cursor} $txn]
86	error_check_good curs_open:dup [is_valid_cursor $curs $db] TRUE
87
88	for {set d [$curs get -first] } {[llength $d] != 0 } \
89	    {set d [$curs get -next] } {
90		set key_set($i) [lindex [lindex $d 0] 0]
91		incr i
92	}
93
94	# Now put in a bunch of duplicates for key 2
95	for { set d 1 } { $d <= 5 } {incr d} {
96		set r [eval {$db put} $txn $flags {$key_set(2) dup_$d}]
97		error_check_good dup:put $r 0
98	}
99
100	# Now put the cursor on key 1
101
102	# Now set the cursor on the first of the duplicate set.
103	set r [$curs get -set $key_set(1)]
104	error_check_bad cursor_get:DB_SET [llength $r] 0
105	set k [lindex [lindex $r 0] 0]
106	set d [lindex [lindex $r 0] 1]
107	error_check_good curs_get:DB_SET:key $k $key_set(1)
108	error_check_good curs_get:DB_SET:data $d datum$key_set(1)
109
110	# Now do the delete
111	set r [$curs del]
112	error_check_good delete $r 0
113
114	# Now check the get current on the cursor.
115	error_check_good curs_get:del [$curs get -current] ""
116
117	# Now do a put on the key
118	set r [eval {$db put} $txn $flags {$key_set(1) new_datum$key_set(1)}]
119	error_check_good put $r 0
120
121	# Do a get
122	set r [eval {$db get} $txn {$key_set(1)}]
123	error_check_good get [lindex [lindex $r 0] 1] new_datum$key_set(1)
124
125	# Recheck cursor
126	error_check_good curs_get:deleted [$curs get -current] ""
127
128	# Move cursor and see if we get the key.
129	set r [$curs get -first]
130	error_check_bad cursor_get:DB_FIRST [llength $r] 0
131	set k [lindex [lindex $r 0] 0]
132	set d [lindex [lindex $r 0] 1]
133	error_check_good curs_get:DB_FIRST:key $k $key_set(1)
134	error_check_good curs_get:DB_FIRST:data $d new_datum$key_set(1)
135
136	puts "\tTest057.b: Set two cursor on a key, delete one, overwrite other"
137	set curs2 [eval {$db cursor} $txn]
138	error_check_good curs2_open [is_valid_cursor $curs2 $db] TRUE
139
140	# Set both cursors on the 4rd key
141	set r [$curs get -set $key_set(3)]
142	error_check_bad cursor_get:DB_SET [llength $r] 0
143	set k [lindex [lindex $r 0] 0]
144	set d [lindex [lindex $r 0] 1]
145	error_check_good curs_get:DB_SET:key $k $key_set(3)
146	error_check_good curs_get:DB_SET:data $d datum$key_set(3)
147
148	set r [$curs2 get -set $key_set(3)]
149	error_check_bad cursor2_get:DB_SET [llength $r] 0
150	set k [lindex [lindex $r 0] 0]
151	set d [lindex [lindex $r 0] 1]
152	error_check_good curs2_get:DB_SET:key $k $key_set(3)
153	error_check_good curs2_get:DB_SET:data $d datum$key_set(3)
154
155	# Now delete through cursor 1
156	error_check_good curs1_del [$curs del] 0
157
158	# Verify gets on both 1 and 2
159	error_check_good curs_get:deleted [$curs get -current] ""
160	error_check_good curs_get:deleted [$curs2 get -current] ""
161
162	puts "\tTest057.c:\
163	    Set two cursors on a dup, delete one, overwrite other"
164
165	# Set both cursors on the 2nd duplicate of key 2
166	set r [$curs get -set $key_set(2)]
167	error_check_bad cursor_get:DB_SET [llength $r] 0
168	set k [lindex [lindex $r 0] 0]
169	set d [lindex [lindex $r 0] 1]
170	error_check_good curs_get:DB_SET:key $k $key_set(2)
171	error_check_good curs_get:DB_SET:data $d datum$key_set(2)
172
173	set r [$curs get -next]
174	error_check_bad cursor_get:DB_NEXT [llength $r] 0
175	set k [lindex [lindex $r 0] 0]
176	set d [lindex [lindex $r 0] 1]
177	error_check_good curs_get:DB_NEXT:key $k $key_set(2)
178	error_check_good curs_get:DB_NEXT:data $d dup_1
179
180	set r [$curs2 get -set $key_set(2)]
181	error_check_bad cursor2_get:DB_SET [llength $r] 0
182	set k [lindex [lindex $r 0] 0]
183	set d [lindex [lindex $r 0] 1]
184	error_check_good curs2_get:DB_SET:key $k $key_set(2)
185	error_check_good curs2_get:DB_SET:data $d datum$key_set(2)
186
187	set r [$curs2 get -next]
188	error_check_bad cursor2_get:DB_NEXT [llength $r] 0
189	set k [lindex [lindex $r 0] 0]
190	set d [lindex [lindex $r 0] 1]
191	error_check_good curs2_get:DB_NEXT:key $k $key_set(2)
192	error_check_good curs2_get:DB_NEXT:data $d dup_1
193
194	# Now delete through cursor 1
195	error_check_good curs1_del [$curs del] 0
196
197	# Verify gets on both 1 and 2
198	error_check_good curs_get:deleted [$curs get -current] ""
199	error_check_good curs_get:deleted [$curs2 get -current] ""
200
201	error_check_good curs2_close [$curs2 close] 0
202	error_check_good curs_close [$curs close] 0
203	if { $txnenv == 1 } {
204		error_check_good txn [$t commit] 0
205	}
206	error_check_good db_close [$db close] 0
207}
208