OLD | NEW |
(Empty) | |
| 1 # 2014 August 16 |
| 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 # |
| 13 |
| 14 if {![info exists testdir]} { |
| 15 set testdir [file join [file dirname [info script]] .. .. test] |
| 16 } |
| 17 source [file join [file dirname [info script]] session_common.tcl] |
| 18 source $testdir/tester.tcl |
| 19 ifcapable !session {finish_test; return} |
| 20 |
| 21 set testprefix sessionC |
| 22 |
| 23 #------------------------------------------------------------------------- |
| 24 # Test the outcome of a DELETE operation made as part of applying a |
| 25 # changeset failing with SQLITE_CONSTRAINT. This may happen if an |
| 26 # ON DELETE RESTRICT foreign key action is triggered, or if a trigger |
| 27 # program raises a constraint somehow. |
| 28 # |
| 29 # UPDATE: The above is no longer true, as "PRAGMA defer_foreign_keys" |
| 30 # now disables "RESTRICT" processing. The test below has been rewritten |
| 31 # to use a trigger instead of a foreign key to test this case. |
| 32 # |
| 33 do_execsql_test 1.0 { |
| 34 PRAGMA foreign_keys = 1; |
| 35 |
| 36 CREATE TABLE p(a PRIMARY KEY, b, c); |
| 37 CREATE TABLE c(d PRIMARY KEY, e /* REFERENCES p ON DELETE RESTRICT */); |
| 38 |
| 39 CREATE TRIGGER restrict_trig BEFORE DELETE ON p BEGIN |
| 40 SELECT raise(ABORT, 'error!') FROM c WHERE e=old.a; |
| 41 END; |
| 42 |
| 43 INSERT INTO p VALUES('one', 1, 1); |
| 44 INSERT INTO p VALUES('two', 2, 2); |
| 45 INSERT INTO p VALUES('three', 3, 3); |
| 46 |
| 47 INSERT INTO c VALUES(1, 'one'); |
| 48 INSERT INTO c VALUES(3, 'three'); |
| 49 } |
| 50 |
| 51 do_test 1.1 { |
| 52 execsql BEGIN |
| 53 set C [changeset_from_sql { |
| 54 INSERT INTO c VALUES(4, 'one'); |
| 55 DELETE FROM p WHERE a='two'; |
| 56 }] |
| 57 execsql ROLLBACK |
| 58 execsql { |
| 59 INSERT INTO c VALUES(2, 'two'); |
| 60 } |
| 61 } {} |
| 62 |
| 63 do_test 1.2.1 { |
| 64 proc xConflict {args} { return "ABORT" } |
| 65 catch { sqlite3changeset_apply db $C xConflict } msg |
| 66 set msg |
| 67 } {SQLITE_ABORT} |
| 68 do_execsql_test 1.2.2 { SELECT * FROM c } {1 one 3 three 2 two} |
| 69 |
| 70 do_test 1.3.1 { |
| 71 proc xConflict {args} { return "OMIT" } |
| 72 catch { sqlite3changeset_apply db $C xConflict } msg |
| 73 set msg |
| 74 } {} |
| 75 do_execsql_test 1.3.2 { SELECT * FROM c } {1 one 3 three 2 two 4 one} |
| 76 do_execsql_test 1.3.3 { |
| 77 SELECT * FROM p; |
| 78 } {one 1 1 two 2 2 three 3 3} |
| 79 |
| 80 |
| 81 #------------------------------------------------------------------------- |
| 82 # Test that concatenating a changeset with a patchset does not work. |
| 83 # Any attempt to do so returns SQLITE_ERROR. |
| 84 # |
| 85 reset_db |
| 86 do_execsql_test 2.0 { |
| 87 CREATE TABLE x1(t, v PRIMARY KEY); |
| 88 INSERT INTO x1 VALUES(12, 55); |
| 89 INSERT INTO x1 VALUES(55, 14); |
| 90 } |
| 91 |
| 92 do_test 2.1 { |
| 93 execsql BEGIN |
| 94 |
| 95 sqlite3session S1 db main |
| 96 S1 attach * |
| 97 execsql { |
| 98 UPDATE x1 SET t=13 WHERE v=55; |
| 99 INSERT INTO x1 VALUES(99, 123); |
| 100 } |
| 101 set patchset [S1 patchset] |
| 102 S1 delete |
| 103 |
| 104 sqlite3session S1 db main |
| 105 S1 attach * |
| 106 execsql { |
| 107 UPDATE x1 SET t=56 WHERE v=14; |
| 108 INSERT INTO x1 VALUES(22, 998); |
| 109 } |
| 110 set changeset [S1 changeset] |
| 111 S1 delete |
| 112 |
| 113 execsql ROLLBACK |
| 114 } {} |
| 115 |
| 116 do_test 2.2 { |
| 117 set rc [catch { sqlite3changeset_concat $patchset $changeset } msg] |
| 118 list $rc $msg |
| 119 } {1 SQLITE_ERROR} |
| 120 |
| 121 do_test 2.3 { |
| 122 set rc [catch { sqlite3changeset_concat $changeset $patchset } msg] |
| 123 list $rc $msg |
| 124 } {1 SQLITE_ERROR} |
| 125 |
| 126 do_test 2.4 { |
| 127 set rc [catch { sqlite3changeset_concat {} $patchset } msg] |
| 128 list $rc $msg |
| 129 } [list 0 $patchset] |
| 130 |
| 131 do_test 2.5 { |
| 132 set rc [catch { sqlite3changeset_concat $patchset {} } msg] |
| 133 list $rc $msg |
| 134 } [list 0 $patchset] |
| 135 |
| 136 do_test 2.6 { |
| 137 set rc [catch { sqlite3changeset_concat {} $changeset } msg] |
| 138 list $rc $msg |
| 139 } [list 0 $changeset] |
| 140 |
| 141 do_test 2.7 { |
| 142 set rc [catch { sqlite3changeset_concat $changeset {} } msg] |
| 143 list $rc $msg |
| 144 } [list 0 $changeset] |
| 145 |
| 146 do_test 2.8 { |
| 147 set rc [catch { sqlite3changeset_concat {} {} } msg] |
| 148 list $rc $msg |
| 149 } [list 0 {}] |
| 150 |
| 151 |
| 152 #------------------------------------------------------------------------- |
| 153 # Test that the xFilter argument to sqlite3changeset_apply() works. |
| 154 # |
| 155 reset_db |
| 156 do_execsql_test 3.0 { |
| 157 CREATE TABLE t1(a PRIMARY KEY, b); |
| 158 CREATE TABLE t2(a PRIMARY KEY, b); |
| 159 CREATE TABLE t3(a PRIMARY KEY, b); |
| 160 } |
| 161 do_test 3.1 { |
| 162 execsql BEGIN |
| 163 set changeset [changeset_from_sql { |
| 164 INSERT INTO t1 VALUES(1, 1); |
| 165 INSERT INTO t2 VALUES(2, 2); |
| 166 INSERT INTO t3 VALUES(3, 3); |
| 167 }] |
| 168 execsql ROLLBACK |
| 169 } {} |
| 170 do_test 3.2 { |
| 171 proc xFilter {zName} { |
| 172 if {$zName == "t1"} { return 1 } |
| 173 return 0 |
| 174 } |
| 175 sqlite3changeset_apply db $changeset noop xFilter |
| 176 execsql { |
| 177 SELECT * FROM t1; |
| 178 SELECT * FROM t2; |
| 179 SELECT * FROM t3; |
| 180 } |
| 181 } {1 1} |
| 182 do_test 3.3 { |
| 183 proc xFilter {zName} { |
| 184 if {$zName == "t3"} { return 1 } |
| 185 return 0 |
| 186 } |
| 187 sqlite3changeset_apply db $changeset noop xFilter |
| 188 execsql { |
| 189 SELECT * FROM t1; |
| 190 SELECT * FROM t2; |
| 191 SELECT * FROM t3; |
| 192 } |
| 193 } {1 1 3 3} |
| 194 |
| 195 |
| 196 |
| 197 finish_test |
| 198 |
OLD | NEW |