summaryrefslogtreecommitdiff
path: root/db-4.8.30/test/siutils.tcl
blob: 71b77d2f4fd55d720253a73623c01acb55463c46 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
#See the file LICENSE for redistribution information.
#
# Copyright (c) 2001-2009 Oracle.  All rights reserved.
#
# $Id$
#
# Secondary index utilities.  This file used to be known as
# sindex.tcl.
#
# The secondary index tests themselves live in si0*.tcl.
#
# Standard number of secondary indices to create if a single-element
# list of methods is passed into the secondary index tests.
global nsecondaries
set nsecondaries 2

# The callback function we use for each given secondary in most tests
# is a simple function of its place in the list of secondaries (0-based)
# and the access method (since recnos may need different callbacks).
#
# !!!
# Note that callbacks 0-3 return unique secondary keys if the input data
# are unique;  callbacks 4 and higher may not, so don't use them with
# the normal wordlist and secondaries that don't support dups.
# The callbacks that incorporate a key don't work properly with recno
# access methods, at least not in the current test framework (the
# error_check_good lines test for e.g. 1foo, when the database has
# e.g. 0x010x000x000x00foo).
proc callback_n { n } {
	switch $n {
		0 { return _s_reversedata }
		1 { return _s_noop }
		2 { return _s_concatkeydata }
		3 { return _s_concatdatakey }
		4 { return _s_reverseconcat }
		5 { return _s_truncdata }
		6 { return _s_constant }
		7 { return _s_twokeys }
		8 { return _s_variablekeys }
	}
	return _s_noop
}

proc _s_noop { a b } { return $b }
proc _s_reversedata { a b } { return [reverse $b] }
proc _s_truncdata { a b } { return [string range $b 1 end] }
proc _s_concatkeydata { a b } { return $a$b }
proc _s_concatdatakey { a b } { return $b$a }
proc _s_reverseconcat { a b } { return [reverse $a$b] }
proc _s_constant { a b } { return "constant-data" }
proc _s_twokeys { a b } { return [list 1 2] }
proc _s_variablekeys { a b } {
	set rlen [string length $b]
	set result {}
	for {set i 0} {$i < $rlen} {incr i} {
		lappend $result $i
	}
	return $result
}

# Should the check_secondary routines print lots of output?
set verbose_check_secondaries 0

# Given a primary database handle, a list of secondary handles, a
# number of entries, and arrays of keys and data, verify that all
# databases have what they ought to.
proc check_secondaries { pdb sdbs nentries keyarr dataarr {pref "Check"} \
    {errp NONE} {errs NONE} {errsg NONE}} {
	upvar $keyarr keys
	upvar $dataarr data
	global verbose_check_secondaries

	if { [string compare $errp NONE] != 0 } {
		upvar $errp errorp
	}
	set errorp 0
	if { [string compare $errs NONE] != 0 } {
		upvar $errs errors
	}
	set errors 0
	if { [string compare $errsg NONE] != 0 } {
		upvar $errsg errorsg
	}
	set errorsg 0
	# Make sure each key/data pair is in the primary.
	if { $verbose_check_secondaries } {
		puts "\t\t$pref.1: Each key/data pair is in the primary"
	}
	for { set i 0 } { $i < $nentries } { incr i } {
		if { [string equal $errp NONE] } {
			error_check_good pdb_get($i) [$pdb get $keys($i)] \
			    [list [list $keys($i) $data($i)]]
		} else {
			set stat [catch {$pdb get $keys($i)} ret]
			if { $stat == 1 } {
				set errorp $ret
				break
			} else {
				error_check_good pdb_get($i) $ret \
				    [list [list $keys($i) $data($i)]]
			}
		}
	}

	for { set j 0 } { $j < [llength $sdbs] } { incr j } {
		# Make sure each key/data pair is in this secondary.
		if { $verbose_check_secondaries } {
			puts "\t\t$pref.2:\
			    Each skey/key/data tuple is in secondary #$j"
		}
		set sdb [lindex $sdbs $j]
		set nskeys 0
		for { set i 0 } { $i < $nentries } { incr i } {
			set skeys [[callback_n $j] $keys($i) $data($i)]
			if { [llength $skeys] == 0 } {
				set skeys [list $skeys]
			}
			foreach skey $skeys {
				incr nskeys
				# Check with pget on the secondary.
				set stat [catch {$sdb pget -get_both \
				    $skey $keys($i)} ret]
				if { [string equal $errs NONE] } {
					error_check_good stat $stat 0
					error_check_good sdb($j)_pget($i) $ret \
					    [list [list \
					    $skey $keys($i) $data($i)]]
				} else {
					if { $stat == 1 } {
						set errors $ret
					} else {
						error_check_good \
						    sdb($j)_pget($i) $ret \
						    [list [list \
						    $skey $keys($i) $data($i)]]
					}
				}
				# Check again with get on the secondary.  Since
				# get_both is not an allowed option with get on
				# a secondary handle, we can't guarantee an
				# exact match on method 5 and over.  We just
				# make sure that one of the returned key/data
				# pairs is the right one.
				if { $j >= 5 } {
					error_check_good sdb($j)_get($i) \
					    [is_substr [$sdb get $skey] \
					    [list [list $skey $data($i)]]] 1
				} else {
					set stat [catch {$sdb get $skey} ret]
					if { [string equal $errs NONE] } {
						error_check_good \
						    sdb($j)_get($i) $ret \
						    [list [list \
						    $skey $data($i)]]
					} else {
						if { $stat == 1 } {
							set errorsg $ret
							break
						} else {
							error_check_good \
							    sdb($j)_get($i) \
							    $ret [list [list \
							    $skey $data($i)]]
						}
					}
				}
				#
				# We couldn't break above because we need to
				# execute the errorsg error as well.
				#
				if { $errors != 0 } {
					break
				}
			}
		}
		if { $errors != 0 || $errorsg != 0 } {
			break
		}

		# Make sure this secondary contains only $nskeys
		# items.
		if { $verbose_check_secondaries } {
			puts "\t\t$pref.3: Secondary #$j has $nskeys items"
		}
		set dbc [$sdb cursor]
		error_check_good dbc($i) \
		    [is_valid_cursor $dbc $sdb] TRUE
		for { set k 0 } { [llength [$dbc get -next]] > 0 } \
		    { incr k } { }
		error_check_good numitems($i) $k $nskeys
		error_check_good dbc($i)_close [$dbc close] 0
	}
	if { $errorp != 0 || $errors != 0 || $errorsg != 0 } {
		return
	}

	if { $verbose_check_secondaries } {
		puts "\t\t$pref.4: Primary has $nentries items"
	}
	set dbc [$pdb cursor]
	error_check_good pdbc [is_valid_cursor $dbc $pdb] TRUE
	for { set k 0 } { [llength [$dbc get -next]] > 0 } { incr k } { }
	error_check_good numitems $k $nentries
	error_check_good pdbc_close [$dbc close] 0
}

# Given a primary database handle and a list of secondary handles, walk
# through the primary and make sure all the secondaries are correct,
# then walk through the secondaries and make sure the primary is correct.
#
# This is slightly less rigorous than the normal check_secondaries--we
# use it whenever we don't have up-to-date "keys" and "data" arrays.
proc cursor_check_secondaries { pdb sdbs nentries { pref "Check" } } {
	global verbose_check_secondaries

	# Make sure each key/data pair in the primary is in each secondary.
	set pdbc [$pdb cursor]
	error_check_good ccs_pdbc [is_valid_cursor $pdbc $pdb] TRUE
	set i 0
	if { $verbose_check_secondaries } {
		puts "\t\t$pref.1:\
		    Key/data in primary => key/data in secondaries"
	}

	for { set dbt [$pdbc get -first] } { [llength $dbt] > 0 } \
	    { set dbt [$pdbc get -next] } {
		incr i
		set pkey [lindex [lindex $dbt 0] 0]
		set pdata [lindex [lindex $dbt 0] 1]
		for { set j 0 } { $j < [llength $sdbs] } { incr j } {
			set sdb [lindex $sdbs $j]
			# Check with pget.
			foreach skey [[callback_n $j] $pkey $pdata] {
			set sdbt [$sdb pget -get_both $skey $pkey]
			error_check_good pkey($pkey,$j) \
			    [lindex [lindex $sdbt 0] 1] $pkey
			error_check_good pdata($pdata,$j) \
			    [lindex [lindex $sdbt 0] 2] $pdata
			}
		}
	}
	error_check_good ccs_pdbc_close [$pdbc close] 0
	error_check_good primary_has_nentries $i $nentries

	for { set j 0 } { $j < [llength $sdbs] } { incr j } {
		if { $verbose_check_secondaries } {
			puts "\t\t$pref.2:\
			    Key/data in secondary #$j => key/data in primary"
		}
		set sdb [lindex $sdbs $j]
		set sdbc [$sdb cursor]
		error_check_good ccs_sdbc($j) [is_valid_cursor $sdbc $sdb] TRUE
		for { set dbt [$sdbc pget -first] } { [llength $dbt] > 0 } \
		    { set dbt [$sdbc pget -next] } {
			set pkey [lindex [lindex $dbt 0] 1]
			set pdata [lindex [lindex $dbt 0] 2]
			error_check_good pdb_get($pkey/$pdata,$j) \
			    [$pdb get -get_both $pkey $pdata] \
			    [list [list $pkey $pdata]]
		}

		# To exercise pget -last/pget -prev, we do it backwards too.
		for { set dbt [$sdbc pget -last] } { [llength $dbt] > 0 } \
		    { set dbt [$sdbc pget -prev] } {
			set pkey [lindex [lindex $dbt 0] 1]
			set pdata [lindex [lindex $dbt 0] 2]
			error_check_good pdb_get_bkwds($pkey/$pdata,$j) \
			    [$pdb get -get_both $pkey $pdata] \
			    [list [list $pkey $pdata]]
		}

		error_check_good ccs_sdbc_close($j) [$sdbc close] 0
	}
}

# The secondary index tests take a list of the access methods that
# each array ought to use.  Convert at one blow into a list of converted
# argses and omethods for each method in the list.
proc convert_argses { methods largs } {
	set ret {}
	foreach m $methods {
		lappend ret [convert_args $m $largs]
	}
	return $ret
}
proc convert_methods { methods } {
	set ret {}
	foreach m $methods {
		lappend ret [convert_method $m]
	}
	return $ret
}