1# 2014 August 30 2# 3# The author disclaims copyright to this source code. In place of 4# a legal notice, here is a blessing: 5# 6# May you do good and not evil. 7# May you find forgiveness for yourself and forgive others. 8# May you share freely, never taking more than you give. 9# 10#*********************************************************************** 11# 12# Test some properties of the pager_rbu_mode and rbu_mode pragmas. 13# 14 15source [file join [file dirname [info script]] rbu_common.tcl] 16set ::testprefix rbu5 17 18 19# Return a list of the primary key columns for table $tbl in the database 20# opened by database handle $db. 21# 22proc pkcols {db tbl} { 23 set ret [list] 24 $db eval "PRAGMA table_info = '$tbl'" { 25 if {$pk} { lappend ret $name } 26 } 27 return $ret 28} 29 30# Return a list of all columns for table $tbl in the database opened by 31# database handle $db. 32# 33proc allcols {db tbl} { 34 set ret [list] 35 $db eval "PRAGMA table_info = '$tbl'" { 36 lappend ret $name 37 } 38 return $ret 39} 40 41# Return a checksum on all tables and data in the main database attached 42# to database handle $db. It is possible to add indexes without changing 43# the checksum. 44# 45proc datacksum {db} { 46 47 $db eval { SELECT name FROM sqlite_master WHERE type='table' } { 48 append txt $name 49 set cols [list] 50 set order [list] 51 set cnt 0 52 $db eval "PRAGMA table_info = $name" x { 53 lappend cols "quote($x(name))" 54 lappend order [incr cnt] 55 } 56 set cols [join $cols ,] 57 set order [join $order ,] 58 append txt [$db eval "SELECT $cols FROM $name ORDER BY $order"] 59 } 60 return "[string length $txt]-[md5 $txt]" 61} 62 63proc ucontrol {args} { 64 set ret "" 65 foreach a $args { 66 if {$a} { 67 append ret . 68 } else { 69 append ret x 70 } 71 } 72 return $ret 73} 74 75# Argument $target is the name of an SQLite database file. $sql is an SQL 76# script containing INSERT, UPDATE and DELETE statements to execute against 77# it. This command creates an RBU update database in file $rbu that has 78# the same effect as the script. The target database is not modified by 79# this command. 80# 81proc generate_rbu_db {target rbu sql} { 82 83 forcedelete $rbu 84 forcecopy $target copy.db 85 86 # Evaluate the SQL script to modify the contents of copy.db. 87 # 88 sqlite3 dbRbu copy.db 89 dbRbu eval $sql 90 91 dbRbu function ucontrol ucontrol 92 93 # Evaluate the SQL script to modify the contents of copy.db. 94 set ret [datacksum dbRbu] 95 96 dbRbu eval { ATTACH $rbu AS rbu } 97 dbRbu eval { ATTACH $target AS orig } 98 99 dbRbu eval { SELECT name AS tbl FROM sqlite_master WHERE type = 'table' } { 100 set pk [pkcols dbRbu $tbl] 101 set cols [allcols dbRbu $tbl] 102 103 # A WHERE clause to test that the PK columns match. 104 # 105 set where [list] 106 foreach c $pk { lappend where "main.$tbl.$c IS orig.$tbl.$c" } 107 set where [join $where " AND "] 108 109 # A WHERE clause to test that all columns match. 110 # 111 set where2 [list] 112 foreach c $cols { lappend where2 "main.$tbl.$c IS orig.$tbl.$c" } 113 set ucontrol "ucontrol([join $where2 ,])" 114 set where2 [join $where2 " AND "] 115 116 # Create a data_xxx table in the RBU update database. 117 dbRbu eval " 118 CREATE TABLE rbu.data_$tbl AS SELECT *, '' AS rbu_control 119 FROM main.$tbl LIMIT 0 120 " 121 122 # Find all new rows INSERTed by the script. 123 dbRbu eval " 124 INSERT INTO rbu.data_$tbl 125 SELECT *, 0 AS rbu_control FROM main.$tbl 126 WHERE NOT EXISTS ( 127 SELECT 1 FROM orig.$tbl WHERE $where 128 ) 129 " 130 131 # Find all old rows DELETEd by the script. 132 dbRbu eval " 133 INSERT INTO rbu.data_$tbl 134 SELECT *, 1 AS rbu_control FROM orig.$tbl 135 WHERE NOT EXISTS ( 136 SELECT 1 FROM main.$tbl WHERE $where 137 ) 138 " 139 140 # Find all rows UPDATEd by the script. 141 set origcols [list] 142 foreach c $cols { lappend origcols "main.$tbl.$c" } 143 set origcols [join $origcols ,] 144 dbRbu eval " 145 INSERT INTO rbu.data_$tbl 146 SELECT $origcols, $ucontrol AS rbu_control 147 FROM orig.$tbl, main.$tbl 148 WHERE $where AND NOT ($where2) 149 " 150 151 } 152 153 dbRbu close 154 forcedelete copy.db 155 156 return $ret 157} 158 159#------------------------------------------------------------------------- 160# 161do_execsql_test 1.0 { 162 CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); 163 CREATE TABLE t2(x, y, z, PRIMARY KEY(y, z)) WITHOUT ROWID; 164 165 INSERT INTO t1 VALUES(1, 2, 3); 166 INSERT INTO t1 VALUES(2, 4, 6); 167 INSERT INTO t1 VALUES(3, 6, 9); 168 169 INSERT INTO t2 VALUES(1, 2, 3); 170 INSERT INTO t2 VALUES(2, 4, 6); 171 INSERT INTO t2 VALUES(3, 6, 9); 172} 173db close 174 175set cksum [generate_rbu_db test.db rbu.db { 176 INSERT INTO t1 VALUES(4, 8, 12); 177 DELETE FROM t1 WHERE a = 2; 178 UPDATE t1 SET c = 15 WHERE a=3; 179 180 INSERT INTO t2 VALUES(4, 8, 12); 181 DELETE FROM t2 WHERE x = 2; 182 UPDATE t2 SET x = 15 WHERE z=9; 183}] 184 185foreach {tn idx} { 186 1 { 187 } 188 2 { 189 CREATE INDEX i1 ON t1(a, b, c); 190 CREATE INDEX i2 ON t2(x, y, z); 191 } 192} { 193 foreach cmd {run step} { 194 forcecopy test.db test.db2 195 forcecopy rbu.db rbu.db2 196 197 sqlite3 db test.db2 198 db eval $idx 199 200 do_test 1.$tn.$cmd.1 { 201 ${cmd}_rbu test.db2 rbu.db2 202 datacksum db 203 } $cksum 204 205 do_test 1.$tn.$cmd.2 { 206 db eval { PRAGMA integrity_check } 207 } {ok} 208 209 db close 210 } 211} 212 213#------------------------------------------------------------------------- 214# 215reset_db 216do_execsql_test 2.0 { 217 CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d, e); 218 INSERT INTO t1 VALUES(-750250,'fyetckfaagjkzqjx',-185831,X'FEAD',444258.29); 219 INSERT INTO t1 VALUES(649081,NULL,X'7DF25BF78778',-342324.63,'akvspktocwozo'); 220 INSERT INTO t1 VALUES(-133045,-44822.31,X'',287935,NULL); 221 INSERT INTO t1 VALUES(202132,NULL,X'5399','cujsjtspryqeyovcdpz','m'); 222 INSERT INTO t1 VALUES(302910,NULL,'dvdhivtfkaedzhdcnn',-717113.41,688487); 223 INSERT INTO t1 VALUES(-582327,X'7A267A',X'7E6B3CFE5CB9','zacuzilrok',-196478); 224 INSERT INTO t1 VALUES(-190462,X'D1A087E7D68D9578','lsmleti',NULL,-928094); 225 INSERT INTO t1 VALUES(-467665,176344.57,-536684.23,828876.22,X'903E'); 226 INSERT INTO t1 VALUES(-629138,632630.29,X'28D6',-774501,X'819BBBFC65'); 227 INSERT INTO t1 VALUES(-828110,-54379.24,-881121.44,X'',X'8D5A894F0D'); 228 229 CREATE TABLE t2(a PRIMARY KEY, b, c, d, e) WITHOUT ROWID; 230 INSERT INTO t2 VALUES(-65174,X'AC1DBFFE27310F',-194471.08,347988,X'84041BA6F9BDDE86A8'); 231 INSERT INTO t2 VALUES('bzbpi',-952693.69,811628.25,NULL,-817434); 232 INSERT INTO t2 VALUES(-643830,NULL,'n',NULL,'dio'); 233 INSERT INTO t2 VALUES('rovoenxxj',NULL,'owupbtdcoxxnvg',-119676,X'55431DFA'); 234 INSERT INTO t2 VALUES(899770,'jlygdl',X'DBCA4D1A',NULL,-631773); 235 INSERT INTO t2 VALUES(334698.80,NULL,-697585.58,-89277,-817352); 236 INSERT INTO t2 VALUES(X'1A9EB7547A4AAF38','aiprdhkpzdz','anw','szvjbwdvzucybpwwqjt',X'53'); 237 INSERT INTO t2 VALUES(713220,NULL,'hfcqhqzjuqplvkum',X'20B076075649DE','fthgpvqdyy'); 238 INSERT INTO t2 VALUES(763908,NULL,'xgslzcpvwfknbr',X'75',X'668146'); 239 INSERT INTO t2 VALUES(X'E1BA2B6BA27278','wjbpd',NULL,139341,-290086.15); 240} 241db close 242 243set cksum [generate_rbu_db test.db rbu.db { 244INSERT INTO t2 VALUES(222916.23,'idh',X'472C517405',X'E3',X'7C4F31824669'); 245INSERT INTO t2 VALUES('xcndjwafcoxwxizoktd',-319567.21,NULL,-720906.43,-577170); 246INSERT INTO t2 VALUES(376369.99,-536058,'yoaiurfqupdscwc',X'29EC8A2542EC3953E9',-740485.22); 247INSERT INTO t2 VALUES(X'0EFB4DC50693',-175590.83,X'1779E253CAB5B1789E',X'BC6903',NULL); 248INSERT INTO t2 VALUES(-288299,'hfrp',NULL,528477,730676.77); 249DELETE FROM t2 WHERE a < -60000; 250 251UPDATE t2 SET b = 'pgnnaaoflnw' WHERE a = 'bzbpi'; 252UPDATE t2 SET c = -675583 WHERE a = 'rovoenxxj'; 253UPDATE t2 SET d = X'09CDF2B2C241' WHERE a = 713220; 254 255INSERT INTO t1 VALUES(224938,'bmruycvfznhhnfmgqys','fr',854381,789143); 256INSERT INTO t1 VALUES(-863931,-1386.26,X'2A058540C2FB5C',NULL,X'F9D5990A'); 257INSERT INTO t1 VALUES(673696,X'97301F0AC5735F44B5',X'440C',227999.92,-709599.79); 258INSERT INTO t1 VALUES(-243640,NULL,-71718.11,X'1EEFEB38',X'8CC7C55D95E142FBA5'); 259INSERT INTO t1 VALUES(275893,X'',375606.30,X'0AF9EC334711FB',-468194); 260DELETE FROM t1 WHERE a > 200000; 261 262UPDATE t1 SET b = 'pgnnaaoflnw' WHERE a = -190462; 263UPDATE t1 SET c = -675583 WHERE a = -467665; 264UPDATE t1 SET d = X'09CDF2B2C241' WHERE a = -133045; 265 266}] 267 268foreach {tn idx} { 269 1 { 270 } 271 2 { 272 CREATE UNIQUE INDEX i1 ON t1(b, c, d); 273 CREATE UNIQUE INDEX i2 ON t1(d, e, a); 274 CREATE UNIQUE INDEX i3 ON t1(e, d, c, b); 275 276 CREATE UNIQUE INDEX i4 ON t2(b, c, d); 277 CREATE UNIQUE INDEX i5 ON t2(d, e, a); 278 CREATE UNIQUE INDEX i6 ON t2(e, d, c, b); 279 } 280} { 281 foreach cmd {run step} { 282 forcecopy test.db test.db2 283 forcecopy rbu.db rbu.db2 284 285 sqlite3 db test.db2 286 db eval $idx 287 288 do_test 2.$tn.$cmd.1 { 289 ${cmd}_rbu test.db2 rbu.db2 290 datacksum db 291 } $cksum 292 293 do_test 2.$tn.$cmd.2 { 294 db eval { PRAGMA integrity_check } 295 } {ok} 296 297 db close 298 } 299} 300 301 302finish_test 303