1# See the file LICENSE for redistribution information.
2#
3# Copyright (c) 1996,2008 Oracle.  All rights reserved.
4#
5# $Id: test057.tcl,v 12.6 2008/01/08 20:58:53 bostic Exp $
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	puts "Test057: $method delete and replace in presence of cursor."
28
29	# Create the database and open the dictionary
30	set txnenv 0
31	set eindex [lsearch -exact $args "-env"]
32	#
33	# If we are using an env, then testfile should just be the db name.
34	# Otherwise it is the test directory and the name.
35	if { $eindex == -1 } {
36		set testfile $testdir/test057.db
37		set env NULL
38	} else {
39		set testfile test057.db
40		incr eindex
41		set env [lindex $args $eindex]
42		set txnenv [is_txnenv $env]
43		if { $txnenv == 1 } {
44			append args " -auto_commit "
45		}
46		set testdir [get_home $env]
47	}
48	cleanup $testdir $env
49
50	set flags ""
51	set txn ""
52
53	set db [eval {berkdb_open} $args {$omethod $testfile}]
54	error_check_good dbopen:dup [is_valid_db $db] TRUE
55
56	puts "\tTest057.a: Set cursor, delete cursor, put with key."
57	# Put three keys in the database
58	for { set key 1 } { $key <= 3 } {incr key} {
59		if { $txnenv == 1 } {
60			set t [$env txn]
61			error_check_good txn [is_valid_txn $t $env] TRUE
62			set txn "-txn $t"
63		}
64		set r [eval {$db put} $txn $flags {$key datum$key}]
65		error_check_good put $r 0
66		if { $txnenv == 1 } {
67			error_check_good txn [$t commit] 0
68		}
69	}
70
71	# Retrieve keys sequentially so we can figure out their order
72	set i 1
73	if { $txnenv == 1 } {
74		set t [$env txn]
75		error_check_good txn [is_valid_txn $t $env] TRUE
76		set txn "-txn $t"
77	}
78	set curs [eval {$db cursor} $txn]
79	error_check_good curs_open:dup [is_valid_cursor $curs $db] TRUE
80
81	for {set d [$curs get -first] } {[llength $d] != 0 } \
82	    {set d [$curs get -next] } {
83		set key_set($i) [lindex [lindex $d 0] 0]
84		incr i
85	}
86
87	# Now put in a bunch of duplicates for key 2
88	for { set d 1 } { $d <= 5 } {incr d} {
89		set r [eval {$db put} $txn $flags {$key_set(2) dup_$d}]
90		error_check_good dup:put $r 0
91	}
92
93	# Now put the cursor on key 1
94
95	# Now set the cursor on the first of the duplicate set.
96	set r [$curs get -set $key_set(1)]
97	error_check_bad cursor_get:DB_SET [llength $r] 0
98	set k [lindex [lindex $r 0] 0]
99	set d [lindex [lindex $r 0] 1]
100	error_check_good curs_get:DB_SET:key $k $key_set(1)
101	error_check_good curs_get:DB_SET:data $d datum$key_set(1)
102
103	# Now do the delete
104	set r [$curs del]
105	error_check_good delete $r 0
106
107	# Now check the get current on the cursor.
108	error_check_good curs_get:del [$curs get -current] ""
109
110	# Now do a put on the key
111	set r [eval {$db put} $txn $flags {$key_set(1) new_datum$key_set(1)}]
112	error_check_good put $r 0
113
114	# Do a get
115	set r [eval {$db get} $txn {$key_set(1)}]
116	error_check_good get [lindex [lindex $r 0] 1] new_datum$key_set(1)
117
118	# Recheck cursor
119	error_check_good curs_get:deleted [$curs get -current] ""
120
121	# Move cursor and see if we get the key.
122	set r [$curs get -first]
123	error_check_bad cursor_get:DB_FIRST [llength $r] 0
124	set k [lindex [lindex $r 0] 0]
125	set d [lindex [lindex $r 0] 1]
126	error_check_good curs_get:DB_FIRST:key $k $key_set(1)
127	error_check_good curs_get:DB_FIRST:data $d new_datum$key_set(1)
128
129	puts "\tTest057.b: Set two cursor on a key, delete one, overwrite other"
130	set curs2 [eval {$db cursor} $txn]
131	error_check_good curs2_open [is_valid_cursor $curs2 $db] TRUE
132
133	# Set both cursors on the 4rd key
134	set r [$curs get -set $key_set(3)]
135	error_check_bad cursor_get:DB_SET [llength $r] 0
136	set k [lindex [lindex $r 0] 0]
137	set d [lindex [lindex $r 0] 1]
138	error_check_good curs_get:DB_SET:key $k $key_set(3)
139	error_check_good curs_get:DB_SET:data $d datum$key_set(3)
140
141	set r [$curs2 get -set $key_set(3)]
142	error_check_bad cursor2_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 curs2_get:DB_SET:key $k $key_set(3)
146	error_check_good curs2_get:DB_SET:data $d datum$key_set(3)
147
148	# Now delete through cursor 1
149	error_check_good curs1_del [$curs del] 0
150
151	# Verify gets on both 1 and 2
152	error_check_good curs_get:deleted [$curs get -current] ""
153	error_check_good curs_get:deleted [$curs2 get -current] ""
154
155	puts "\tTest057.c:\
156	    Set two cursors on a dup, delete one, overwrite other"
157
158	# Set both cursors on the 2nd duplicate of key 2
159	set r [$curs get -set $key_set(2)]
160	error_check_bad cursor_get:DB_SET [llength $r] 0
161	set k [lindex [lindex $r 0] 0]
162	set d [lindex [lindex $r 0] 1]
163	error_check_good curs_get:DB_SET:key $k $key_set(2)
164	error_check_good curs_get:DB_SET:data $d datum$key_set(2)
165
166	set r [$curs get -next]
167	error_check_bad cursor_get:DB_NEXT [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_NEXT:key $k $key_set(2)
171	error_check_good curs_get:DB_NEXT:data $d dup_1
172
173	set r [$curs2 get -set $key_set(2)]
174	error_check_bad cursor2_get:DB_SET [llength $r] 0
175	set k [lindex [lindex $r 0] 0]
176	set d [lindex [lindex $r 0] 1]
177	error_check_good curs2_get:DB_SET:key $k $key_set(2)
178	error_check_good curs2_get:DB_SET:data $d datum$key_set(2)
179
180	set r [$curs2 get -next]
181	error_check_bad cursor2_get:DB_NEXT [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_NEXT:key $k $key_set(2)
185	error_check_good curs2_get:DB_NEXT:data $d dup_1
186
187	# Now delete through cursor 1
188	error_check_good curs1_del [$curs del] 0
189
190	# Verify gets on both 1 and 2
191	error_check_good curs_get:deleted [$curs get -current] ""
192	error_check_good curs_get:deleted [$curs2 get -current] ""
193
194	error_check_good curs2_close [$curs2 close] 0
195	error_check_good curs_close [$curs close] 0
196	if { $txnenv == 1 } {
197		error_check_good txn [$t commit] 0
198	}
199	error_check_good db_close [$db close] 0
200}
201