OLD | NEW |
1 # 2015-07-31 | 1 # 2015-07-31 |
2 # | 2 # |
3 # The author disclaims copyright to this source code. In place of | 3 # The author disclaims copyright to this source code. In place of |
4 # a legal notice, here is a blessing: | 4 # a legal notice, here is a blessing: |
5 # | 5 # |
6 # May you do good and not evil. | 6 # May you do good and not evil. |
7 # May you find forgiveness for yourself and forgive others. | 7 # May you find forgiveness for yourself and forgive others. |
8 # May you share freely, never taking more than you give. | 8 # May you share freely, never taking more than you give. |
9 # | 9 # |
10 #*********************************************************************** | 10 #*********************************************************************** |
11 # | 11 # |
12 # Tests for the [sqldiff --rbu] command. | 12 # Tests for the [sqldiff --rbu] command. |
13 # | 13 # |
14 # | 14 # |
15 if {![info exists testdir]} { | 15 if {![info exists testdir]} { |
16 set testdir [file join [file dirname [info script]] .. .. test] | 16 set testdir [file join [file dirname [info script]] .. .. test] |
17 } | 17 } |
18 source $testdir/tester.tcl | 18 source $testdir/tester.tcl |
19 set testprefix rbudiff | 19 set testprefix rbudiff |
20 | 20 |
21 if {$tcl_platform(platform)=="windows"} { | 21 set PROG [test_find_sqldiff] |
22 set PROG "sqldiff.exe" | |
23 } else { | |
24 set PROG "./sqldiff" | |
25 } | |
26 if {![file exe $PROG]} { | |
27 puts "rbudiff.test cannot run because $PROG is not available" | |
28 finish_test | |
29 return | |
30 } | |
31 db close | 22 db close |
32 | 23 |
33 proc get_rbudiff_sql {db1 db2} { | 24 proc get_rbudiff_sql {db1 db2} { |
34 exec $::PROG --rbu $db1 $db2 | 25 exec $::PROG --rbu $db1 $db2 |
35 } | 26 } |
36 | 27 |
| 28 proc get_vtab_rbudiff_sql {db1 db2} { |
| 29 exec $::PROG --vtab --rbu $db1 $db2 |
| 30 } |
| 31 |
37 proc step_rbu {target rbu} { | 32 proc step_rbu {target rbu} { |
38 while 1 { | 33 while 1 { |
39 sqlite3rbu rbu $target $rbu | 34 sqlite3rbu rbu $target $rbu |
40 set rc [rbu step] | 35 set rc [rbu step] |
41 rbu close | 36 rbu close |
42 if {$rc != "SQLITE_OK"} break | 37 if {$rc != "SQLITE_OK"} break |
43 } | 38 } |
44 set rc | 39 set rc |
45 } | 40 } |
46 | 41 |
47 proc apply_rbudiff {sql target} { | 42 proc apply_rbudiff {sql target} { |
| 43 test_rbucount $sql |
48 forcedelete rbu.db | 44 forcedelete rbu.db |
49 sqlite3 rbudb rbu.db | 45 sqlite3 rbudb rbu.db |
50 rbudb eval $sql | 46 rbudb eval $sql |
51 rbudb close | 47 rbudb close |
52 step_rbu $target rbu.db | 48 step_rbu $target rbu.db |
53 } | 49 } |
54 | 50 |
| 51 proc sqlesc {id} { |
| 52 set ret "'[string map {' ''} $id]'" |
| 53 set ret |
| 54 } |
| 55 |
| 56 # The only argument is the output of an [sqldiff -rbu] run. This command |
| 57 # tests that the contents of the rbu_count table is correct. An exception |
| 58 # is thrown if it is not. |
| 59 # |
| 60 proc test_rbucount {sql} { |
| 61 sqlite3 tmpdb "" |
| 62 tmpdb eval $sql |
| 63 tmpdb eval { |
| 64 SELECT name FROM sqlite_master WHERE name LIKE 'data%' AND type='table' |
| 65 } { |
| 66 set a [tmpdb eval "SELECT count(*) FROM [sqlesc $name]"] |
| 67 set b [tmpdb eval {SELECT cnt FROM rbu_count WHERE tbl = $name}] |
| 68 if {$a != $b} { |
| 69 tmpdb close |
| 70 error "rbu_count error - tbl = $name" |
| 71 } |
| 72 } |
| 73 tmpdb close |
| 74 return "" |
| 75 } |
| 76 |
55 proc rbudiff_cksum {db1} { | 77 proc rbudiff_cksum {db1} { |
56 set txt "" | 78 set txt "" |
57 | 79 |
58 sqlite3 dbtmp $db1 | 80 sqlite3 dbtmp $db1 |
59 foreach tbl [dbtmp eval {SELECT name FROM sqlite_master WHERE type='table'}] { | 81 foreach tbl [dbtmp eval {SELECT name FROM sqlite_master WHERE type='table'}] { |
60 set cols [list] | 82 set cols [list] |
61 dbtmp eval "PRAGMA table_info = $tbl" { lappend cols "quote( $name )" } | 83 dbtmp eval "PRAGMA table_info = [sqlesc $tbl]" { |
| 84 lappend cols "quote( $name )" |
| 85 } |
62 append txt [dbtmp eval \ | 86 append txt [dbtmp eval \ |
63 "SELECT [join $cols {||'.'||}] FROM $tbl ORDER BY 1" | 87 "SELECT [join $cols {||'.'||}] FROM [sqlesc $tbl] ORDER BY 1" |
64 ] | 88 ] |
65 } | 89 } |
66 dbtmp close | 90 dbtmp close |
67 | 91 |
68 md5 $txt | 92 md5 $txt |
69 } | 93 } |
70 | 94 |
71 foreach {tn init mod} { | 95 foreach {tn init mod} { |
72 1 { | 96 1 { |
73 CREATE TABLE t1(a PRIMARY KEY, b, c); | 97 CREATE TABLE t1(a PRIMARY KEY, b, c); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 DELETE FROM t1; | 133 DELETE FROM t1; |
110 INSERT INTO t1 VALUES(1, | 134 INSERT INTO t1 VALUES(1, |
111 X'0000000000000000111111111111111122222555555552223333333333333333' | 135 X'0000000000000000111111111111111122222555555552223333333333333333' |
112 ); | 136 ); |
113 DELETE FROM t2; | 137 DELETE FROM t2; |
114 INSERT INTO t2 VALUES(1, | 138 INSERT INTO t2 VALUES(1, |
115 X'0000000000000000111111111111111122222222222222223333333FFF333333' | 139 X'0000000000000000111111111111111122222222222222223333333FFF333333' |
116 ); | 140 ); |
117 } | 141 } |
118 | 142 |
| 143 4 { |
| 144 CREATE TABLE x1(a, b, c, PRIMARY KEY(a, b, c)); |
| 145 INSERT INTO x1 VALUES('u', 'v', NULL); |
| 146 INSERT INTO x1 VALUES('x', 'y', 'z'); |
| 147 INSERT INTO x1 VALUES('a', NULL, 'b'); |
| 148 } { |
| 149 INSERT INTO x1 VALUES('a', 'b', 'c'); |
| 150 } |
| 151 |
| 152 5 { |
| 153 CREATE TABLE t1(a PRIMARY KEY, b); |
| 154 INSERT INTO t1 VALUES(1, NULL); |
| 155 INSERT INTO t1 VALUES(2, X''); |
| 156 } { |
| 157 UPDATE t1 SET b = X'' WHERE a=1; |
| 158 UPDATE t1 SET b = NULL WHERE a=2; |
| 159 } |
| 160 |
119 } { | 161 } { |
120 catch { db close } | 162 catch { db close } |
121 | 163 |
122 forcedelete test.db test.db2 | 164 forcedelete test.db test.db2 |
123 sqlite3 db test.db | 165 sqlite3 db test.db |
124 db eval "$init" | 166 db eval "$init" |
125 sqlite3 db test.db2 | 167 sqlite3 db test.db2 |
126 db eval "$init ; $mod" | 168 db eval "$init ; $mod" |
127 db close | 169 db close |
128 | 170 |
(...skipping 10 matching lines...) Expand all Loading... |
139 db eval "$init" | 181 db eval "$init" |
140 db close | 182 db close |
141 | 183 |
142 do_test 1.$tn.4 { | 184 do_test 1.$tn.4 { |
143 set sql [get_rbudiff_sql test.db test.db2] | 185 set sql [get_rbudiff_sql test.db test.db2] |
144 apply_rbudiff $sql test.db | 186 apply_rbudiff $sql test.db |
145 } {SQLITE_DONE} | 187 } {SQLITE_DONE} |
146 do_test 1.$tn.5 { rbudiff_cksum test.db } [rbudiff_cksum test.db2] | 188 do_test 1.$tn.5 { rbudiff_cksum test.db } [rbudiff_cksum test.db2] |
147 } | 189 } |
148 | 190 |
| 191 #------------------------------------------------------------------------- |
| 192 # Test that if the --vtab switch is present, [sqldiff] handles virtual |
| 193 # table types fts[345] and rtree correctly. |
| 194 # |
| 195 ifcapable fts3&&fts5&&rtree { |
| 196 |
| 197 foreach {tn init mod} { |
| 198 1 { |
| 199 CREATE VIRTUAL TABLE t1 USING fts5(c); |
| 200 INSERT INTO t1 VALUES('a b c'); |
| 201 INSERT INTO t1 VALUES('a b c'); |
| 202 } { |
| 203 DELETE FROM t1 WHERE rowid = 1; |
| 204 INSERT INTO t1 VALUES('a b c'); |
| 205 } |
| 206 |
| 207 2 { |
| 208 CREATE VIRTUAL TABLE "x y" USING 'rtree'(id, x1, x2); |
| 209 INSERT INTO "x y" VALUES(1, 2, 3); |
| 210 INSERT INTO "x y" VALUES(2, 4, 6); |
| 211 } { |
| 212 DELETE FROM "x y" WHERE rowid = 1; |
| 213 INSERT INTO "x y" VALUES(3, 6, 9); |
| 214 } |
| 215 |
| 216 3 { |
| 217 CREATE VIRTUAL TABLE 'x''y' USING fts3; |
| 218 INSERT INTO 'x''y' VALUES('one two three'); |
| 219 INSERT INTO 'x''y' VALUES('four five six'); |
| 220 } { |
| 221 DELETE FROM 'x''y' WHERE rowid = 1; |
| 222 INSERT INTO 'x''y' VALUES('one two three'); |
| 223 } |
| 224 } { |
| 225 |
| 226 forcedelete test.db test.db2 |
| 227 sqlite3 db test.db |
| 228 db eval "$init" |
| 229 sqlite3 db test.db2 |
| 230 db eval "$init ; $mod" |
| 231 db close |
| 232 |
| 233 do_test 2.$tn.1 { |
| 234 set sql [get_vtab_rbudiff_sql test.db test.db2] |
| 235 apply_rbudiff $sql test.db |
| 236 } {SQLITE_DONE} |
| 237 do_test 2.$tn.2 { rbudiff_cksum test.db } [rbudiff_cksum test.db2] |
| 238 } |
| 239 |
| 240 } |
| 241 |
| 242 ifcapable fts5 { |
| 243 foreach {tn init mod} { |
| 244 1 { |
| 245 CREATE VIRTUAL TABLE t1 USING fts5(c); |
| 246 INSERT INTO t1 VALUES('a b c'); |
| 247 INSERT INTO t1 VALUES('a b c'); |
| 248 } { |
| 249 DELETE FROM t1 WHERE rowid = 1; |
| 250 INSERT INTO t1 VALUES('a b c'); |
| 251 } |
| 252 |
| 253 2 { |
| 254 CREATE VIRTUAL TABLE t1 USING FTs5(c); |
| 255 INSERT INTO t1 VALUES('a b c'); |
| 256 INSERT INTO t1 VALUES('a b c'); |
| 257 } { |
| 258 DELETE FROM t1 WHERE rowid = 1; |
| 259 INSERT INTO t1 VALUES('a b c'); |
| 260 } |
| 261 |
| 262 3 { |
| 263 creAte virTUal |
| 264 tablE t1 USING FTs5(c); |
| 265 INSERT INTO t1 VALUES('a b c'); |
| 266 INSERT INTO t1 VALUES('a b c'); |
| 267 } { |
| 268 DELETE FROM t1 WHERE rowid = 1; |
| 269 INSERT INTO t1 VALUES('a b c'); |
| 270 } |
| 271 |
| 272 } { |
| 273 forcedelete test.db test.db2 |
| 274 sqlite3 db test.db |
| 275 db eval "$init" |
| 276 sqlite3 db test.db2 |
| 277 db eval "$init ; $mod" |
| 278 db eval { INSERT INTO t1(t1) VALUES('optimize') } |
| 279 db close |
| 280 |
| 281 do_test 3.$tn.1 { |
| 282 set sql [get_vtab_rbudiff_sql test.db test.db2] |
| 283 apply_rbudiff $sql test.db |
| 284 } {SQLITE_DONE} |
| 285 |
| 286 sqlite3 db test.db |
| 287 sqlite3 db2 test.db2 |
| 288 do_test 3.$tn.2 { |
| 289 db2 eval { SELECT * FROM t1 ORDER BY rowid } |
| 290 } [db eval { SELECT * FROM t1 ORDER BY rowid }] |
| 291 |
| 292 do_test 3.$tn.3 { |
| 293 db2 eval { INSERT INTO t1(t1) VALUES('integrity-check') } |
| 294 } {} |
| 295 |
| 296 db close |
| 297 db2 close |
| 298 } |
| 299 } |
| 300 |
| 301 |
149 finish_test | 302 finish_test |
150 | 303 |
OLD | NEW |